3.2 consumer proxy invocation handler (#11108)
* add dubbo mvc feign client to support mvc remote call * add dubbo mvc dispatcher servlet * add dubbo mvc dispatcher servlet * add MvcDispatcherServlet unit test * add dubbo mvc feign client to support mvc remote call * add dubbo mvc dispatcher servlet * add Dubbo mvc Provider RPCInvocation create * mvc remove unused code * remove mvc unused test code * remove unused code * BodyProviderParamParser param type modify * modify pom dependency version * add dubbo-metadata-api dependency * 新增依赖Jakarta支持 tomcat10 * ApplicationModel load ParamParser * ParamParser header & param map convert * ParamParser header & param map convert * 1 增加mvc协议 2 删除多余的resource包 * 1 增加mvc协议 2 增加netter server for http * 重构 NettyHttpClient NettyHttpServer * add path parse util & requestTemplate * add mvc consumer http-connection * mvc change HttpConnectionPreBuildIntercept name and add SerializeBodyIntercept extend * 1. 迁移mvc代码到rest下,合并http统一解析逻辑 2. 删除多余新增的remoting 调用模块 * 解决报错 * 1 抽象http 调用 2 改造rest调用风格 * 修改方法命名 * 修改方法名 * 删除多余的clients * 还原restprotocol,逻辑迁移至新分支 3.2_refactor_rest_protocol * add provider PathMatcher * add ServiceRestMetadata PathMatcher * add ServiceRestMetadata PathMatcher * add jax_rs and mvc annotation class constants * refactor PathMatcher name * add annotation class * maintain rest metadata * maintain jax_rs and mvc annotation * maintain jax_rs and mvc annotation * remove mvc module * remove rest mvc code to code review * add springmvc & rest annotation api module * add springmvc & rest annotation api module * add pathMatcher equal test * remove mvc module * rest provider RPCInvocation build * RPCInvocation build add dubbo-metadata-api dependency * RestMethodMetadata add method to consumer service map * RestMethodMetadata add method to consumer service map * rest consumer HttpInvokeInvocationHandler * rest consumer HttpInvokeInvocationHandler * add dubbo-metadata-api dependency * dubbo-rpc pom fix * 移动模块 * 删除模块引用 * consumer metadata resolve * RestProtocol consumer * RestProtocol consumer * requestConvert adaptive * JSON serializeObject to outputStream * JsonUtilsTest serialize & unSerialize * ok http client * http client reconstruct * rest protocol BaseConvert * rest protocol ParamParser reconstruct * rest protocol addKeepAliveHeader * requestTemplate isBodyEmpty() * remove unused code * create ConsumerParseContext * body default byte[0] * rest http message decode * writeTextContent & writeJsonContent & writeFormContent * remove mvc & rest annotation module * remove provider code * fix some pr advice * Add ASF license header for newly created files * move RestClientFactory code to dubbo-remoting-http * exact request convert code to a factory class * modify request convert code * modify dubbo-dependencies-bom * modify dubbo-remoting-http pom * refactor spi resource file name * dubbo-metadata-api remove dubbo-configcenter-zookeeper dependency for cyclic reference * newly create file add ASF * fix compile error * Enhance Code * add rest protocol ConsumerParamParser * some fix * rest json content-type test * RestProtocol merge doRefer code to protocolBindingRefer * remove restInvoker * rest protocol add JsonFactory to support custom * rest protocol add JsonFactory to support custom * jaxrs rest ParamNoAnnotatedProcessor support fix * add rest http message encode * add rest http message encode * rest okHttpClient requestBody fix * rest jaxrs form content-type support * RestProtocol protocolBindingRefer reconstruct * RestProtocol protocolBindingRefer reconstruct object to invoker & Invocation * move RequestTemplate to remoting-http * rest unit test * add httpclient & url connection rest client * Enhance invocation * enhance * add ParameterTypesComparator for metadataMap * add ASF for new file * Fix conflict * Fix header * fix import * fix import * fix import * fix import * fix import * Fix json * revert some change * Remove jsonfactory * Remove jsonfactory * Simplify rest client * Fix protocol * fix codec * tmp disable test * rest metadata resolver add interface judge * add rest metadata resolve unit test & fix AbstractServiceRestMetadataResolver * org.apache.dubbo.metadata.rest.ParamType null exclude & add default accept header * RestProtocolTest refer add context path unit test * some fix * ADD TODO * RESOLVE HTTP client java.net.SocketException: socket closed * RESOLVE HTTP client java.net.SocketException: socket closed * add spring mvc rest protocol unit test * rest protocol http response code deal * rest protocol http response message * fix some review advice * fix some review advice * add rest metadata resolve unit test & fix AbstractServiceRestMetadataResolver * org.apache.dubbo.metadata.rest.ParamType null exclude & add default accept header * RestProtocolTest refer add context path unit test * some fix * fix some review advice * add spring mvc rest protocol unit test * rest protocol http response code deal * rest protocol http response message * URLConnectionRestClient getMessage * remove unused import * import fix * code merge * code merge * code merge * code merge * code merge * Fix conflicts * change restResult InputStream to bytes protect from fd leak * merge code * Fix import * Fix import * Fix uts * Remove unused code * Fix logger * Update okhttp version * Update okhttp version * rest protocol add AnotherUserRestService service ut * rest protocol add String & byteArray codec * Fix version * Fix uts * rest protocol add XMLCodec * stream release * ServiceRestMetadata port change int to Integer * service RestMetadata service map init * xml codec change for xxe * Fix import * code style * code style * Fix shade --------- Co-authored-by: suncr <suncairong@moresec.cn> Co-authored-by: Liujunjie <42363259+LiujunjieALiling@users.noreply.github.com> Co-authored-by: junjie3.liu <junjie3.liu@ximalaya.com> Co-authored-by: Albumen Kevin <jhq0812@gmail.com>
This commit is contained in:
parent
10e7162268
commit
02a59e2f40
|
|
@ -48,5 +48,4 @@ public interface JSON {
|
|||
List<Map<String, ?>> checkObjectList(List<?> rawList);
|
||||
|
||||
List<String> checkStringList(List<?> rawList);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import java.lang.reflect.Type;
|
|||
import java.util.List;
|
||||
|
||||
public class FastJson2Impl extends AbstractJSONImpl {
|
||||
|
||||
@Override
|
||||
public <T> T toJavaObject(String json, Type type) {
|
||||
return com.alibaba.fastjson2.JSON.parseObject(json, type);
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ public class FastJsonImpl extends AbstractJSONImpl {
|
|||
public String toJson(Object obj) {
|
||||
return com.alibaba.fastjson.JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.json.impl;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
|
||||
|
|
@ -25,6 +27,7 @@ import java.lang.reflect.Type;
|
|||
import java.util.List;
|
||||
|
||||
public class JacksonImpl extends AbstractJSONImpl {
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private volatile Object jacksonCache = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import org.apache.dubbo.metadata.definition.model.MethodDefinition;
|
|||
import org.apache.dubbo.metadata.definition.model.TypeDefinition;
|
||||
import org.apache.dubbo.metadata.definition.service.ComplexObject;
|
||||
import org.apache.dubbo.metadata.definition.service.DemoService;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
|
@ -134,4 +132,4 @@ class ServiceDefinitionBuilderTest {
|
|||
Assertions.assertEquals(Integer.class.getCanonicalName(), listTypeDefinition.getItems().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,5 +35,19 @@
|
|||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-rest</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Web MVC -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Web MVC -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -16,18 +16,26 @@
|
|||
*/
|
||||
package org.apache.dubbo.demo;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
|
||||
import po.TestPO;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
|
||||
@Path("/demoService")
|
||||
public interface RestDemoService {
|
||||
@GET
|
||||
@Path("/hello")
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b);
|
||||
|
||||
@GET
|
||||
|
|
@ -42,4 +50,44 @@ public interface RestDemoService {
|
|||
@GET
|
||||
@Path("/getRemoteApplicationName")
|
||||
String getRemoteApplicationName();
|
||||
|
||||
@POST
|
||||
@Path("/testBody1")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
Integer testBody(Integer b);
|
||||
|
||||
@POST
|
||||
@Path("/testBody2")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
String testBody2(String b);
|
||||
|
||||
@POST
|
||||
@Path("/testBody3")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
Boolean testBody2(Boolean b);
|
||||
|
||||
@POST
|
||||
@Path("/testBody3")
|
||||
@Consumes({MediaType.TEXT_PLAIN})
|
||||
TestPO testBody2(TestPO b);
|
||||
|
||||
|
||||
@POST
|
||||
@Path("/testBody5")
|
||||
@Consumes({MediaType.APPLICATION_JSON})
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
TestPO testBody5(TestPO testPO);
|
||||
|
||||
@POST
|
||||
@Path("/testForm1")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
String testForm1(@FormParam("name") String test);
|
||||
|
||||
|
||||
@POST
|
||||
@Path("/testForm2")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
MultivaluedMap testForm2(MultivaluedMap map);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 po;
|
||||
|
||||
public class TestPO {
|
||||
private String name;
|
||||
private String address;
|
||||
private int age;
|
||||
|
||||
public TestPO(String name, String address, int age) {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public TestPO() {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public static TestPO getInstance() {
|
||||
return new TestPO("dubbo", "hangzhou", 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TestPO{" +
|
||||
"name='" + name + '\'' +
|
||||
", address='" + address + '\'' +
|
||||
", age=" + age +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,11 @@ import org.apache.dubbo.demo.RestDemoService;
|
|||
import org.apache.dubbo.demo.TripleService;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import po.TestPO;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class Application {
|
||||
|
|
@ -56,23 +60,22 @@ public class Application {
|
|||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
String restResult = restDemoService.sayHello("rest");
|
||||
Object restResult = restDemoService.sayHello("rest");
|
||||
System.out.println(restResult + " from separated thread.");
|
||||
restResult = restDemoService.testBody5(TestPO.getInstance());
|
||||
System.out.println(restResult + " from separated thread.");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
String restResult = tripleService.hello();
|
||||
restResult = restDemoService.hello(1, 2);
|
||||
System.out.println(restResult + " from separated thread.");
|
||||
|
||||
String form1 = restDemoService.testForm1("form1");
|
||||
System.out.println(form1);
|
||||
|
||||
MultivaluedHashMap multivaluedHashMap = new MultivaluedHashMap();
|
||||
multivaluedHashMap.put("1", Arrays.asList("1"));
|
||||
multivaluedHashMap.put("2", Arrays.asList("2"));
|
||||
MultivaluedMap form2 = restDemoService.testForm2(multivaluedHashMap);
|
||||
System.out.println(form2);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ package org.apache.dubbo.demo.provider;
|
|||
|
||||
import org.apache.dubbo.demo.RestDemoService;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import po.TestPO;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RestDemoServiceImpl implements RestDemoService {
|
||||
|
|
@ -55,4 +57,39 @@ public class RestDemoServiceImpl implements RestDemoService {
|
|||
public String getRemoteApplicationName() {
|
||||
return RpcContext.getServiceContext().getRemoteApplicationName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer testBody(Integer b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String testBody2(String b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean testBody2(Boolean b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestPO testBody2(TestPO b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestPO testBody5(TestPO testPO) {
|
||||
return testPO;
|
||||
}
|
||||
|
||||
|
||||
public String testForm1(String test) {
|
||||
return test;
|
||||
}
|
||||
|
||||
|
||||
public MultivaluedMap testForm2(MultivaluedMap map) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@
|
|||
<protobuf-java_version>3.19.6</protobuf-java_version>
|
||||
<javax_annotation-api_version>1.3.2</javax_annotation-api_version>
|
||||
<servlet_version>3.1.0</servlet_version>
|
||||
<jakarta.servlet_version>5.0.0</jakarta.servlet_version>
|
||||
<jetty_version>9.4.50.v20221201</jetty_version>
|
||||
<validation_new_version>3.0.1</validation_new_version>
|
||||
<validation_version>1.1.0.Final</validation_version>
|
||||
|
|
@ -139,6 +140,7 @@
|
|||
<prometheus_client.version>0.16.0</prometheus_client.version>
|
||||
<reactive.version>1.0.4</reactive.version>
|
||||
<reactor.version>3.5.2</reactor.version>
|
||||
<okhttp_version>4.10.0</okhttp_version>
|
||||
|
||||
<rs_api_version>2.1.1</rs_api_version>
|
||||
<resteasy_version>3.15.3.Final</resteasy_version>
|
||||
|
|
@ -419,6 +421,25 @@
|
|||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>${servlet_version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- support higher tomcat -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>${jakarta.servlet_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>${okhttp_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
|
|
|||
|
|
@ -906,6 +906,36 @@
|
|||
META-INF/dubbo/internal/org.apache.dubbo.registry.xds.XdsCertificateSigner
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.metadata.rest.NoAnnotatedParameterRequestTagProcessor
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionPreBuildIntercept
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.consumer.BaseConsumerParamParser
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
META-INF/dubbo/internal/org.apache.dubbo.remoting.http.factory.RestClientFactory
|
||||
</resource>
|
||||
</transformer>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>
|
||||
|
|
|
|||
|
|
@ -45,14 +45,6 @@
|
|||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-configcenter-zookeeper</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JAX-RS API -->
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ import static java.util.Collections.emptySet;
|
|||
import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static java.util.stream.Stream.of;
|
||||
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_FAILED_LOAD_MAPPING_CACHE;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY;
|
||||
import static org.apache.dubbo.common.utils.CollectionUtils.toTreeSet;
|
||||
|
|
|
|||
|
|
@ -16,16 +16,30 @@
|
|||
*/
|
||||
package org.apache.dubbo.metadata;
|
||||
|
||||
public class MetadataConstants {
|
||||
public static final String KEY_SEPARATOR = ":";
|
||||
public static final String DEFAULT_PATH_TAG = "metadata";
|
||||
public static final String KEY_REVISON_PREFIX = "revision";
|
||||
public static final String META_DATA_STORE_TAG = ".metaData";
|
||||
public static final String SERVICE_META_DATA_STORE_TAG = ".smd";
|
||||
public static final String CONSUMER_META_DATA_STORE_TAG = ".cmd";
|
||||
public static final String METADATA_PUBLISH_DELAY_KEY = "dubbo.application.metadata.publish.delay";
|
||||
public static final int DEFAULT_METADATA_PUBLISH_DELAY = 1000;
|
||||
public static final String METADATA_PROXY_TIMEOUT_KEY = "dubbo.application.metadata.proxy.delay";
|
||||
public static final int DEFAULT_METADATA_TIMEOUT_VALUE = 5000;
|
||||
public static String REPORT_CONSUMER_URL_KEY = "report-consumer-definition";
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
|
||||
|
||||
public interface MetadataConstants {
|
||||
String KEY_SEPARATOR = ":";
|
||||
String DEFAULT_PATH_TAG = "metadata";
|
||||
String KEY_REVISON_PREFIX = "revision";
|
||||
String META_DATA_STORE_TAG = ".metaData";
|
||||
String SERVICE_META_DATA_STORE_TAG = ".smd";
|
||||
String CONSUMER_META_DATA_STORE_TAG = ".cmd";
|
||||
String METADATA_PUBLISH_DELAY_KEY = "dubbo.application.metadata.publish.delay";
|
||||
int DEFAULT_METADATA_PUBLISH_DELAY = 1000;
|
||||
String METADATA_PROXY_TIMEOUT_KEY = "dubbo.application.metadata.proxy.delay";
|
||||
int DEFAULT_METADATA_TIMEOUT_VALUE = 5000;
|
||||
String REPORT_CONSUMER_URL_KEY = "report-consumer-definition";
|
||||
String JAVAX_SERVLET_REQ_CLASS_NAME = "javax.servlet.ServletRequest";
|
||||
Class JAVAX_SERVLET_REQ_CLASS = resolveClass(JAVAX_SERVLET_REQ_CLASS_NAME, getClassLoader());
|
||||
String JAVAX_SERVLET_RES_CLASS_NAME = "javax.servlet.ServletResponse";
|
||||
Class JAVAX_SERVLET_RES_CLASS = resolveClass(JAVAX_SERVLET_RES_CLASS_NAME, getClassLoader());
|
||||
String JAKARTA_SERVLET_REQ_CLASS_NAME = "jakarta.servlet.ServletRequest";
|
||||
Class JAKARTA_SERVLET_REQ_CLASS = resolveClass(JAKARTA_SERVLET_REQ_CLASS_NAME, getClassLoader());
|
||||
String JAKARTA_SERVLET_RES_CLASS_NAME = "jakarta.servlet.ServletResponse";
|
||||
Class JAKARTA_SERVLET_RES_CLASS = resolveClass(JAKARTA_SERVLET_RES_CLASS_NAME, getClassLoader());
|
||||
String PATH_SEPARATOR = "/";
|
||||
String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
|
||||
String APPLICATION_JSON_VALUE = "application/json";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.dubbo.metadata;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ParameterTypesComparator {
|
||||
|
||||
private Class[] parameterTypes;
|
||||
|
||||
|
||||
public ParameterTypesComparator(Class[] parameterTypes) {
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ParameterTypesComparator that = (ParameterTypesComparator) o;
|
||||
return Arrays.equals(parameterTypes, that.parameterTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(parameterTypes);
|
||||
}
|
||||
|
||||
|
||||
public static ParameterTypesComparator getInstance(Class[] parameterTypes) {
|
||||
return new ParameterTypesComparator(parameterTypes);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -16,12 +16,14 @@
|
|||
*/
|
||||
package org.apache.dubbo.metadata.rest;
|
||||
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.common.utils.AnnotationUtils.getValue;
|
||||
import static org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor.buildDefaultValue;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
|
||||
|
||||
/**
|
||||
* The abstract {@link AnnotatedMethodParameterProcessor} implementation
|
||||
|
|
@ -33,19 +35,39 @@ public abstract class AbstractAnnotatedMethodParameterProcessor implements Annot
|
|||
@Override
|
||||
public void process(Annotation annotation, Parameter parameter, int parameterIndex, Method method,
|
||||
Class<?> serviceType, Class<?> serviceInterfaceClass, RestMethodMetadata restMethodMetadata) {
|
||||
|
||||
String annotationValue = getAnnotationValue(annotation, parameter, parameterIndex);
|
||||
String defaultValue = getDefaultValue(annotation, parameter, parameterIndex);
|
||||
addArgInfo(parameter, parameterIndex, restMethodMetadata, annotationValue, defaultValue);
|
||||
process(annotationValue, defaultValue, annotation, parameter, parameterIndex, method, restMethodMetadata);
|
||||
}
|
||||
|
||||
|
||||
protected void process(String annotationValue, String defaultValue, Annotation annotation, Parameter parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Class getAnnotationClass() {
|
||||
return resolveClass(getAnnotationName(), getClassLoader());
|
||||
}
|
||||
|
||||
protected void addArgInfo(Parameter parameter, int parameterIndex,
|
||||
RestMethodMetadata restMethodMetadata, String annotationValue, Object defaultValue) {
|
||||
ArgInfo argInfo = ArgInfo.build(parameterIndex, parameter)
|
||||
.setParamAnnotationType(getAnnotationClass())
|
||||
.setAnnotationNameAttribute(annotationValue).setDefaultValue(defaultValue);
|
||||
restMethodMetadata.addArgInfo(argInfo);
|
||||
}
|
||||
|
||||
protected String getAnnotationValue(Annotation annotation, Parameter parameter, int parameterIndex) {
|
||||
return getValue(annotation);
|
||||
}
|
||||
|
||||
protected String getDefaultValue(Annotation annotation, Parameter parameter, int parameterIndex) {
|
||||
return buildDefaultValue(parameterIndex);
|
||||
return AnnotatedMethodParameterProcessor.buildDefaultValue(parameterIndex);
|
||||
}
|
||||
|
||||
protected abstract void process(String annotationValue, String defaultValue, Annotation annotation, Object parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
|
||||
|
||||
public abstract class AbstractNoAnnotatedParameterProcessor implements NoAnnotatedParameterRequestTagProcessor {
|
||||
|
||||
public void process(Parameter parameter, int parameterIndex, RestMethodMetadata restMethodMetadata) {
|
||||
MediaType mediaType = consumerContentType();
|
||||
if (!contentTypeSupport(restMethodMetadata, mediaType, parameter.getType())) {
|
||||
return;
|
||||
}
|
||||
boolean isFormBody = isFormContentType(restMethodMetadata);
|
||||
addArgInfo(parameter, parameterIndex, restMethodMetadata, isFormBody);
|
||||
}
|
||||
|
||||
private boolean contentTypeSupport(RestMethodMetadata restMethodMetadata, MediaType mediaType, Class paramType) {
|
||||
|
||||
// @RequestParam String,number param
|
||||
if (mediaType.equals(MediaType.ALL_VALUE) && (String.class == paramType || Number.class.isAssignableFrom(paramType))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Set<String> consumes = restMethodMetadata.getRequest().getConsumes();
|
||||
for (String consume : consumes) {
|
||||
if (consume.contains(mediaType.value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isFormContentType(RestMethodMetadata restMethodMetadata) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected void addArgInfo(Parameter parameter, int parameterIndex,
|
||||
RestMethodMetadata restMethodMetadata, boolean isFormBody) {
|
||||
ArgInfo argInfo = ArgInfo.build(parameterIndex, parameter)
|
||||
.setParamAnnotationType(resolveClass(defaultAnnotationClassName(restMethodMetadata), getClassLoader()))
|
||||
.setAnnotationNameAttribute(parameter.getName()).setFormContentType(isFormBody);
|
||||
restMethodMetadata.addArgInfo(argInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ import static org.apache.dubbo.common.function.ThrowableFunction.execute;
|
|||
import static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.forName;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces;
|
||||
import static org.apache.dubbo.common.utils.MemberUtils.isPrivate;
|
||||
import static org.apache.dubbo.common.utils.MemberUtils.isStatic;
|
||||
import static org.apache.dubbo.common.utils.MethodUtils.excludedDeclaredClass;
|
||||
import static org.apache.dubbo.common.utils.MethodUtils.getAllMethods;
|
||||
import static org.apache.dubbo.common.utils.MethodUtils.overrides;
|
||||
|
|
@ -56,13 +58,27 @@ import static org.apache.dubbo.common.utils.MethodUtils.overrides;
|
|||
public abstract class AbstractServiceRestMetadataResolver implements ServiceRestMetadataResolver {
|
||||
|
||||
private final Map<String, List<AnnotatedMethodParameterProcessor>> parameterProcessorsMap;
|
||||
private final Set<NoAnnotatedParameterRequestTagProcessor> noAnnotatedParameterRequestTagProcessors;
|
||||
|
||||
public AbstractServiceRestMetadataResolver(ApplicationModel applicationModel) {
|
||||
this.parameterProcessorsMap = loadAnnotatedMethodParameterProcessors(applicationModel);
|
||||
this.noAnnotatedParameterRequestTagProcessors = loadNoAnnotatedMethodParameterProcessors(applicationModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean supports(Class<?> serviceType) {
|
||||
return supports(serviceType, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean supports(Class<?> serviceType, boolean consumer) {
|
||||
// for consumer
|
||||
if (consumer) {
|
||||
// it is possible serviceType is impl
|
||||
return supports0(serviceType);
|
||||
}
|
||||
|
||||
// for provider
|
||||
return isImplementedInterface(serviceType) && isServiceAnnotationPresent(serviceType) && supports0(serviceType);
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +88,7 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
|
||||
protected final boolean isServiceAnnotationPresent(Class<?> serviceType) {
|
||||
return isAnyAnnotationPresent(serviceType, DubboService.class, Service.class,
|
||||
com.alibaba.dubbo.config.annotation.Service.class);
|
||||
com.alibaba.dubbo.config.annotation.Service.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -85,12 +101,18 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
|
||||
@Override
|
||||
public final ServiceRestMetadata resolve(Class<?> serviceType) {
|
||||
|
||||
ServiceRestMetadata serviceRestMetadata = new ServiceRestMetadata();
|
||||
|
||||
// Process ServiceRestMetadata
|
||||
processServiceRestMetadata(serviceRestMetadata, serviceType);
|
||||
|
||||
return resolve(serviceType, serviceRestMetadata);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final ServiceRestMetadata resolve(Class<?> serviceType, ServiceRestMetadata serviceRestMetadata) {
|
||||
serviceRestMetadata.setCodeStyle(this.getClass());
|
||||
// Process RestMethodMetadata
|
||||
processAllRestMethodMetadata(serviceRestMetadata, serviceType);
|
||||
|
||||
|
|
@ -128,10 +150,10 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
// try the overrider method first
|
||||
Method serviceMethod = entry.getKey();
|
||||
// If failed, it indicates the overrider method does not contain metadata , then try the declared method
|
||||
if (!processRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, serviceRestMetadata.getMeta()::add)) {
|
||||
if (!processRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, serviceRestMetadata::addRestMethodMetadata)) {
|
||||
Method declaredServiceMethod = entry.getValue();
|
||||
processRestMethodMetadata(declaredServiceMethod, serviceType, serviceInterfaceClass,
|
||||
serviceRestMetadata.getMeta()::add);
|
||||
serviceRestMetadata::addRestMethodMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -148,8 +170,16 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
Map<Method, Method> serviceMethodsMap = new LinkedHashMap<>();
|
||||
// exclude the public methods declared in java.lang.Object.class
|
||||
List<Method> declaredServiceMethods = new ArrayList<>(getAllMethods(serviceInterfaceClass, excludedDeclaredClass(Object.class)));
|
||||
|
||||
// for interface , such as consumer interface
|
||||
if (serviceType.isInterface()) {
|
||||
putInterfaceMethodToMap(serviceMethodsMap, declaredServiceMethods);
|
||||
return unmodifiableMap(serviceMethodsMap);
|
||||
}
|
||||
|
||||
List<Method> serviceMethods = new ArrayList<>(getAllMethods(serviceType, excludedDeclaredClass(Object.class)));
|
||||
|
||||
|
||||
// sort methods
|
||||
sort(declaredServiceMethods, MethodComparator.INSTANCE);
|
||||
sort(serviceMethods, MethodComparator.INSTANCE);
|
||||
|
|
@ -158,7 +188,8 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
for (Method serviceMethod : serviceMethods) {
|
||||
if (overrides(serviceMethod, declaredServiceMethod)) {
|
||||
serviceMethodsMap.put(serviceMethod, declaredServiceMethod);
|
||||
continue;
|
||||
// once method match ,break for decrease loop times
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,6 +197,17 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
return unmodifiableMap(serviceMethodsMap);
|
||||
}
|
||||
|
||||
private void putInterfaceMethodToMap(Map<Method, Method> serviceMethodsMap, List<Method> declaredServiceMethods) {
|
||||
declaredServiceMethods.stream().forEach(method -> {
|
||||
|
||||
// filter static private default
|
||||
if (isStatic(method) || isPrivate(method) || method.isDefault()) {
|
||||
return;
|
||||
}
|
||||
serviceMethodsMap.put(method, method);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the class of Dubbo Service interface
|
||||
*
|
||||
|
|
@ -212,13 +254,15 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
|
||||
RestMethodMetadata metadata = new RestMethodMetadata();
|
||||
|
||||
metadata.setCodeStyle(this.getClass());
|
||||
|
||||
// to consumer service map
|
||||
metadata.setReflectMethod(serviceMethod);
|
||||
|
||||
MethodDefinition methodDefinition = resolveMethodDefinition(serviceMethod, serviceType, serviceInterfaceClass);
|
||||
// Set MethodDefinition
|
||||
metadata.setMethod(methodDefinition);
|
||||
|
||||
// process the annotated method parameters
|
||||
processAnnotatedMethodParameters(serviceMethod, serviceType, serviceInterfaceClass, metadata);
|
||||
|
||||
// process produces
|
||||
Set<String> produces = new LinkedHashSet<>();
|
||||
processProduces(serviceMethod, serviceType, serviceInterfaceClass, produces);
|
||||
|
|
@ -234,6 +278,10 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
request.setProduces(produces);
|
||||
request.setConsumes(consumes);
|
||||
|
||||
// process the annotated method parameters
|
||||
processAnnotatedMethodParameters(serviceMethod, serviceType, serviceInterfaceClass, metadata);
|
||||
|
||||
|
||||
// Post-Process
|
||||
postResolveRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, metadata);
|
||||
|
||||
|
|
@ -252,7 +300,7 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
* @return If capable, return <code>true</code>
|
||||
*/
|
||||
protected abstract boolean isRestCapableMethod(Method serviceMethod, Class<?> serviceType, Class<?>
|
||||
serviceInterfaceClass);
|
||||
serviceInterfaceClass);
|
||||
|
||||
/**
|
||||
* Resolve the request method
|
||||
|
|
@ -263,7 +311,7 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
* @return if can't be resolve, return <code>null</code>
|
||||
*/
|
||||
protected abstract String resolveRequestMethod(Method serviceMethod, Class<?> serviceType, Class<?>
|
||||
serviceInterfaceClass);
|
||||
serviceInterfaceClass);
|
||||
|
||||
/**
|
||||
* Resolve the request path
|
||||
|
|
@ -274,7 +322,7 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
* @return if can't be resolve, return <code>null</code>
|
||||
*/
|
||||
protected abstract String resolveRequestPath(Method serviceMethod, Class<?> serviceType, Class<?>
|
||||
serviceInterfaceClass);
|
||||
serviceInterfaceClass);
|
||||
|
||||
/**
|
||||
* Resolve the {@link MethodDefinition}
|
||||
|
|
@ -307,37 +355,56 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest
|
|||
Class<?> serviceType, Class<?> serviceInterfaceClass,
|
||||
RestMethodMetadata metadata) {
|
||||
Annotation[] annotations = parameter.getAnnotations();
|
||||
|
||||
if (annotations == null || annotations.length == 0) {
|
||||
|
||||
for (NoAnnotatedParameterRequestTagProcessor processor : noAnnotatedParameterRequestTagProcessors) {
|
||||
processor.process(parameter, parameterIndex, metadata);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (Annotation annotation : annotations) {
|
||||
String annotationType = annotation.annotationType().getName();
|
||||
parameterProcessorsMap.getOrDefault(annotationType, emptyList())
|
||||
.forEach(processor -> {
|
||||
processor.process(annotation, parameter, parameterIndex, serviceMethod, serviceType,
|
||||
serviceInterfaceClass, metadata);
|
||||
});
|
||||
.forEach(processor -> {
|
||||
processor.process(annotation, parameter, parameterIndex, serviceMethod, serviceType,
|
||||
serviceInterfaceClass, metadata);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processProduces(Method serviceMethod, Class<?> serviceType, Class<?>
|
||||
serviceInterfaceClass,
|
||||
serviceInterfaceClass,
|
||||
Set<String> produces);
|
||||
|
||||
protected abstract void processConsumes(Method serviceMethod, Class<?> serviceType, Class<?>
|
||||
serviceInterfaceClass,
|
||||
serviceInterfaceClass,
|
||||
Set<String> consumes);
|
||||
|
||||
protected void postResolveRestMethodMetadata(Method serviceMethod, Class<?> serviceType,
|
||||
Class<?> serviceInterfaceClass, RestMethodMetadata metadata) {
|
||||
|
||||
// parse pathVariable index from url by annotation info
|
||||
PathUtil.setArgInfoSplitIndex(metadata.getRequest().getPath(), metadata.getArgInfos());
|
||||
}
|
||||
|
||||
private static Map<String, List<AnnotatedMethodParameterProcessor>> loadAnnotatedMethodParameterProcessors(ApplicationModel applicationModel) {
|
||||
Map<String, List<AnnotatedMethodParameterProcessor>> parameterProcessorsMap = new LinkedHashMap<>();
|
||||
applicationModel.getExtensionLoader(AnnotatedMethodParameterProcessor.class)
|
||||
.getSupportedExtensionInstances()
|
||||
.forEach(processor -> {
|
||||
List<AnnotatedMethodParameterProcessor> processors =
|
||||
parameterProcessorsMap.computeIfAbsent(processor.getAnnotationType(), k -> new LinkedList<>());
|
||||
processors.add(processor);
|
||||
});
|
||||
.getSupportedExtensionInstances()
|
||||
.forEach(processor -> {
|
||||
List<AnnotatedMethodParameterProcessor> processors =
|
||||
parameterProcessorsMap.computeIfAbsent(processor.getAnnotationName(), k -> new LinkedList<>());
|
||||
processors.add(processor);
|
||||
});
|
||||
return parameterProcessorsMap;
|
||||
}
|
||||
|
||||
private static Set<NoAnnotatedParameterRequestTagProcessor> loadNoAnnotatedMethodParameterProcessors(ApplicationModel applicationModel) {
|
||||
Set<NoAnnotatedParameterRequestTagProcessor> supportedExtensionInstances = applicationModel.getExtensionLoader(NoAnnotatedParameterRequestTagProcessor.class)
|
||||
.getSupportedExtensionInstances();
|
||||
|
||||
return supportedExtensionInstances;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.common.lang.Prioritized;
|
||||
|
||||
|
|
@ -29,20 +30,28 @@ import java.lang.reflect.Parameter;
|
|||
*
|
||||
* @since 2.7.6
|
||||
*/
|
||||
@SPI
|
||||
@SPI(scope = ExtensionScope.FRAMEWORK)
|
||||
public interface AnnotatedMethodParameterProcessor extends Prioritized {
|
||||
|
||||
/**
|
||||
* The string presenting the annotation name
|
||||
*
|
||||
* @return non-null
|
||||
*/
|
||||
String getAnnotationName();
|
||||
|
||||
|
||||
/**
|
||||
* The string presenting the annotation type
|
||||
*
|
||||
* @return non-null
|
||||
*/
|
||||
String getAnnotationType();
|
||||
Class getAnnotationClass();
|
||||
|
||||
/**
|
||||
* Process the specified method {@link VariableElement parameter}
|
||||
*
|
||||
* @param annotation {@link Annotation the target annotation} whose type is {@link #getAnnotationType()}
|
||||
* @param annotation {@link Annotation the target annotation} whose type is {@link #getAnnotationName()}
|
||||
* @param parameter the method parameter
|
||||
* @param parameterIndex the index of method parameter
|
||||
* @param method {@link Method method that parameter belongs to}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
public class ArgInfo {
|
||||
/**
|
||||
* method arg index 0,1,2,3
|
||||
*/
|
||||
private int index;
|
||||
/**
|
||||
* method annotation name or name
|
||||
*/
|
||||
private String annotationNameAttribute;
|
||||
|
||||
/**
|
||||
* param annotation type
|
||||
*/
|
||||
private Class paramAnnotationType;
|
||||
|
||||
/**
|
||||
* param Type
|
||||
*/
|
||||
private Class paramType;
|
||||
|
||||
/**
|
||||
* param name
|
||||
*/
|
||||
private String paramName;
|
||||
|
||||
/**
|
||||
* url split("/") String[n] index
|
||||
*/
|
||||
private int urlSplitIndex;
|
||||
|
||||
private Object defaultValue;
|
||||
|
||||
private boolean formContentType;
|
||||
|
||||
public ArgInfo(int index, String name, Class paramType) {
|
||||
this.index = index;
|
||||
this.paramName = name;
|
||||
this.paramType = paramType;
|
||||
}
|
||||
|
||||
public ArgInfo(int index, Parameter parameter) {
|
||||
this(index, parameter.getName(), parameter.getType());
|
||||
}
|
||||
|
||||
public ArgInfo() {
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public ArgInfo setIndex(int index) {
|
||||
this.index = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAnnotationNameAttribute() {
|
||||
if (annotationNameAttribute == null) {
|
||||
// such as String param no annotation
|
||||
return paramName;
|
||||
}
|
||||
return annotationNameAttribute;
|
||||
}
|
||||
|
||||
public ArgInfo setAnnotationNameAttribute(String annotationNameAttribute) {
|
||||
this.annotationNameAttribute = annotationNameAttribute;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class getParamAnnotationType() {
|
||||
return paramAnnotationType;
|
||||
}
|
||||
|
||||
public ArgInfo setParamAnnotationType(Class paramAnnotationType) {
|
||||
this.paramAnnotationType = paramAnnotationType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class getParamType() {
|
||||
return paramType;
|
||||
}
|
||||
|
||||
public void setParamType(Class paramType) {
|
||||
this.paramType = paramType;
|
||||
}
|
||||
|
||||
|
||||
public int getUrlSplitIndex() {
|
||||
return urlSplitIndex;
|
||||
}
|
||||
|
||||
public void setUrlSplitIndex(int urlSplitIndex) {
|
||||
this.urlSplitIndex = urlSplitIndex;
|
||||
}
|
||||
|
||||
public static ArgInfo build() {
|
||||
return new ArgInfo();
|
||||
}
|
||||
|
||||
public static ArgInfo build(int index, Parameter parameter) {
|
||||
return new ArgInfo(index, parameter);
|
||||
}
|
||||
|
||||
public String getParamName() {
|
||||
return paramName;
|
||||
}
|
||||
|
||||
public ArgInfo setParamName(String paramName) {
|
||||
this.paramName = paramName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public ArgInfo setDefaultValue(Object defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFormContentType() {
|
||||
return formContentType;
|
||||
}
|
||||
|
||||
public ArgInfo setFormContentType(boolean isFormContentType) {
|
||||
this.formContentType = isFormContentType;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
|
||||
|
||||
public interface JAXRSClassConstants extends RestMetadataConstants.JAX_RS {
|
||||
/**
|
||||
* The annotation class of @Path
|
||||
*/
|
||||
Class PATH_ANNOTATION_CLASS = resolveClass(PATH_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @FormParam
|
||||
*/
|
||||
Class FORM_PARAM_ANNOTATION_CLASS = resolveClass(FORM_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
/**
|
||||
* The annotation class of @HeaderParam
|
||||
*/
|
||||
Class HEADER_PARAM_ANNOTATION_CLASS = resolveClass(HEADER_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @MatrixParam
|
||||
*/
|
||||
Class MATRIX_PARAM_ANNOTATION_CLASS = resolveClass(MATRIX_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @QueryParam
|
||||
*/
|
||||
Class QUERY_PARAM_ANNOTATION_CLASS = resolveClass(QUERY_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
/**
|
||||
* The annotation class of @Body
|
||||
*/
|
||||
Class REST_EASY_BODY_ANNOTATION_CLASS = resolveClass(REST_EASY_BODY_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
/**
|
||||
* The annotation class of @PathParam
|
||||
*/
|
||||
Class PATH_PARAM_ANNOTATION_CLASS = resolveClass(PATH_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
@SPI(scope = ExtensionScope.FRAMEWORK)
|
||||
public interface NoAnnotatedParameterRequestTagProcessor {
|
||||
MediaType consumerContentType();
|
||||
|
||||
String defaultAnnotationClassName(RestMethodMetadata restMethodMetadata);
|
||||
|
||||
void process(Parameter parameter, int parameterIndex, RestMethodMetadata restMethodMetadata);
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.metadata.MetadataConstants;
|
||||
import org.apache.dubbo.metadata.rest.tag.BodyTag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public enum ParamType {
|
||||
HEADER(addSupportTypes(JAXRSClassConstants.HEADER_PARAM_ANNOTATION_CLASS,
|
||||
SpringMvcClassConstants.REQUEST_HEADER_ANNOTATION_CLASS)),
|
||||
|
||||
PARAM(addSupportTypes(JAXRSClassConstants.QUERY_PARAM_ANNOTATION_CLASS,
|
||||
SpringMvcClassConstants.REQUEST_PARAM_ANNOTATION_CLASS)),
|
||||
|
||||
BODY(addSupportTypes(
|
||||
JAXRSClassConstants.REST_EASY_BODY_ANNOTATION_CLASS,
|
||||
SpringMvcClassConstants.REQUEST_BODY_ANNOTATION_CLASS, BodyTag.class)),
|
||||
// TODO how to match arg type ?
|
||||
REQ_OR_RES(addSupportTypes(MetadataConstants.JAKARTA_SERVLET_REQ_CLASS,
|
||||
MetadataConstants.JAKARTA_SERVLET_RES_CLASS,
|
||||
MetadataConstants.JAVAX_SERVLET_REQ_CLASS,
|
||||
MetadataConstants.JAKARTA_SERVLET_RES_CLASS)),
|
||||
|
||||
PATH(addSupportTypes(JAXRSClassConstants.PATH_PARAM_ANNOTATION_CLASS,
|
||||
SpringMvcClassConstants.PATH_VARIABLE_ANNOTATION_CLASS)),
|
||||
|
||||
FORM(addSupportTypes(JAXRSClassConstants.FORM_PARAM_ANNOTATION_CLASS)),
|
||||
|
||||
EMPTY(addSupportTypes());
|
||||
private List<Class> annotationClasses;
|
||||
|
||||
|
||||
ParamType(List<Class> annotationClasses) {
|
||||
this.annotationClasses = annotationClasses;
|
||||
}
|
||||
|
||||
|
||||
public boolean supportAnno(Class anno) {
|
||||
if (anno == null) {
|
||||
return false;
|
||||
}
|
||||
return this.annotationClasses.contains(anno);
|
||||
}
|
||||
|
||||
public boolean isReqOrRes(Class clazz) {
|
||||
for (Class annotationClass : annotationClasses) {
|
||||
if (annotationClass.isAssignableFrom(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* exclude null types
|
||||
*
|
||||
* @param classes
|
||||
* @return
|
||||
*/
|
||||
private static List<Class> addSupportTypes(Class... classes) {
|
||||
|
||||
ArrayList<Class> types = new ArrayList<>();
|
||||
|
||||
for (Class clazz : classes) {
|
||||
|
||||
if (clazz == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
types.add(clazz);
|
||||
}
|
||||
|
||||
return types;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class PathMatcher {
|
||||
private static final String SEPARATOR = "/";
|
||||
private String path;
|
||||
private String version;
|
||||
private String group;
|
||||
private Integer port;
|
||||
private String[] pathSplits;
|
||||
private boolean hasPathVariable;
|
||||
|
||||
|
||||
public PathMatcher(String path) {
|
||||
this(path, null, null, 0);
|
||||
}
|
||||
|
||||
public PathMatcher(String path, String version, String group, Integer port) {
|
||||
this.path = path;
|
||||
this.pathSplits = path.split(SEPARATOR);
|
||||
|
||||
for (String pathSplit : pathSplits) {
|
||||
|
||||
if (isPlaceHold(pathSplit)) {
|
||||
hasPathVariable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.version = version;
|
||||
this.group = group;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PathMatcher that = (PathMatcher) o;
|
||||
return pathEqual(that.path) && Objects.equals(version, that.version)
|
||||
&& Objects.equals(group, that.group) && Objects.equals(port, that.port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(version, group, port);
|
||||
}
|
||||
|
||||
private boolean pathEqual(String path) {
|
||||
|
||||
// no place hold
|
||||
if (!hasPathVariable) {
|
||||
return this.path.equals(path);
|
||||
}
|
||||
|
||||
String[] split = path.split(SEPARATOR);
|
||||
|
||||
|
||||
if (split.length != pathSplits.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pathSplits.length; i++) {
|
||||
boolean equals = split[i].equals(pathSplits[i]);
|
||||
if (equals) {
|
||||
continue;
|
||||
} else {
|
||||
if (placeHoldCompare(pathSplits[i])) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private boolean placeHoldCompare(String pathSplit) {
|
||||
boolean startAndEndEqual = isPlaceHold(pathSplit);
|
||||
|
||||
// start { end }
|
||||
if (!startAndEndEqual) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// exclude {}
|
||||
boolean lengthCondition = pathSplit.length() >= 3;
|
||||
|
||||
if (!lengthCondition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isPlaceHold(String pathSplit) {
|
||||
return pathSplit.startsWith("{") && pathSplit.endsWith("}");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathMather{" +
|
||||
"path='" + path + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
", group='" + group + '\'' +
|
||||
", port='" + port + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
|
||||
import org.apache.dubbo.metadata.MetadataConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* is used to parse url pathVariable
|
||||
* <p>
|
||||
* String[] splits= url.split("/")
|
||||
* List<String> strings = Arrays.asList(split);
|
||||
* strings.set(UrlSplitIndex, (String) args.get(argIndex));
|
||||
*/
|
||||
public class PathUtil {
|
||||
private static final String SEPARATOR = MetadataConstants.PATH_SEPARATOR;
|
||||
|
||||
/**
|
||||
* generate real path from rawPath according to argInfo and method args
|
||||
*
|
||||
* @param rawPath
|
||||
* @param argInfos
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public static String resolvePathVariable(String rawPath, List<ArgInfo> argInfos, List<Object> args) {
|
||||
|
||||
String[] split = rawPath.split(SEPARATOR);
|
||||
|
||||
List<String> strings = Arrays.asList(split);
|
||||
|
||||
List<ArgInfo> pathArgInfos = new ArrayList<>();
|
||||
|
||||
for (ArgInfo argInfo : argInfos) {
|
||||
if (ParamType.PATH.supportAnno(argInfo.getParamAnnotationType())) {
|
||||
pathArgInfos.add(argInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (ArgInfo pathArgInfo : pathArgInfos) {
|
||||
strings.set(pathArgInfo.getUrlSplitIndex(), String.valueOf(args.get(pathArgInfo.getIndex())));
|
||||
}
|
||||
|
||||
|
||||
String pat = SEPARATOR;
|
||||
|
||||
for (String string : strings) {
|
||||
|
||||
if (string.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pat = pat + string + SEPARATOR;
|
||||
}
|
||||
|
||||
if (pat.endsWith(SEPARATOR)) {
|
||||
pat = pat.substring(0, pat.lastIndexOf(SEPARATOR));
|
||||
}
|
||||
|
||||
return pat;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* parse pathVariable index from url by annotation info
|
||||
*
|
||||
* @param rawPath
|
||||
* @param argInfos
|
||||
*/
|
||||
public static void setArgInfoSplitIndex(String rawPath, List<ArgInfo> argInfos) {
|
||||
String[] split = rawPath.split(SEPARATOR);
|
||||
|
||||
List<PathPair> pathPairs = new ArrayList<>();
|
||||
|
||||
for (ArgInfo argInfo : argInfos) {
|
||||
if (ParamType.PATH.supportAnno(argInfo.getParamAnnotationType())) {
|
||||
pathPairs.add(new PathPair(argInfo));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String s = split[i];
|
||||
for (PathPair pathPair : pathPairs) {
|
||||
boolean match = pathPair.match(s);
|
||||
if (match) {
|
||||
pathPair.setArgInfoSplitIndex(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PathPair {
|
||||
|
||||
String value;
|
||||
|
||||
ArgInfo argInfo;
|
||||
|
||||
|
||||
public PathPair(ArgInfo argInfo) {
|
||||
this.argInfo = argInfo;
|
||||
this.value = argInfo.getAnnotationNameAttribute();
|
||||
}
|
||||
|
||||
public String getPatten() {
|
||||
return "{" + value + "}";
|
||||
}
|
||||
|
||||
public String getLeftPatten() {
|
||||
return "{" + value;
|
||||
}
|
||||
|
||||
public String getRightPatten() {
|
||||
return "}";
|
||||
}
|
||||
|
||||
public boolean match(String value) {
|
||||
return getPatten().equals(value)// for : {id}
|
||||
|| (value.startsWith(getLeftPatten()) && value.endsWith(getRightPatten()));// for : {id: \d+}
|
||||
}
|
||||
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setArgInfo(ArgInfo argInfo) {
|
||||
this.argInfo = argInfo;
|
||||
}
|
||||
|
||||
public void setArgInfoSplitIndex(int urlSplitIndex) {
|
||||
this.argInfo.setUrlSplitIndex(urlSplitIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -55,6 +55,7 @@ public class RequestMetadata implements Serializable {
|
|||
|
||||
private Set<String> produces = new LinkedHashSet<>();
|
||||
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
|
|
@ -202,12 +203,12 @@ public class RequestMetadata implements Serializable {
|
|||
}
|
||||
RequestMetadata that = (RequestMetadata) o;
|
||||
return Objects.equals(method, that.method)
|
||||
&& Objects.equals(path, that.path)
|
||||
&& Objects.equals(consumes, that.consumes)
|
||||
&& Objects.equals(produces, that.produces) &&
|
||||
// Metadata should not compare the values
|
||||
Objects.equals(getParamNames(), that.getParamNames())
|
||||
&& Objects.equals(getHeaderNames(), that.getHeaderNames());
|
||||
&& Objects.equals(path, that.path)
|
||||
&& Objects.equals(consumes, that.consumes)
|
||||
&& Objects.equals(produces, that.produces) &&
|
||||
// Metadata should not compare the values
|
||||
Objects.equals(getParamNames(), that.getParamNames())
|
||||
&& Objects.equals(getHeaderNames(), that.getHeaderNames());
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -215,13 +216,13 @@ public class RequestMetadata implements Serializable {
|
|||
public int hashCode() {
|
||||
// The values of metadata should not use for the hashCode() method
|
||||
return Objects.hash(method, path, consumes, produces, getParamNames(),
|
||||
getHeaderNames());
|
||||
getHeaderNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RequestMetadata{" + "method='" + method + '\'' + ", path='" + path + '\''
|
||||
+ ", params=" + params + ", headers=" + headers + ", consumes=" + consumes
|
||||
+ ", produces=" + produces + '}';
|
||||
+ ", params=" + params + ", headers=" + headers + ", consumes=" + consumes
|
||||
+ ", produces=" + produces + '}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,16 @@ public interface RestMetadataConstants {
|
|||
* The annotation class name of @QueryParam
|
||||
*/
|
||||
String QUERY_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.QueryParam";
|
||||
|
||||
/**
|
||||
* The annotation class name of @Body
|
||||
*/
|
||||
String REST_EASY_BODY_ANNOTATION_CLASS_NAME = "org.jboss.resteasy.annotations.Body";
|
||||
|
||||
/**
|
||||
* The annotation class name of @PathParam
|
||||
*/
|
||||
String PATH_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.PathParam";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -114,6 +124,16 @@ public interface RestMetadataConstants {
|
|||
*/
|
||||
String REQUEST_PARAM_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestParam";
|
||||
|
||||
/**
|
||||
* The annotation class name of @RequestBody
|
||||
*/
|
||||
String REQUEST_BODY_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestBody";
|
||||
|
||||
/**
|
||||
* The annotation class name of @PathVariable
|
||||
*/
|
||||
String PATH_VARIABLE_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.PathVariable";
|
||||
|
||||
/**
|
||||
* The class of @Controller
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ package org.apache.dubbo.metadata.rest;
|
|||
import org.apache.dubbo.metadata.definition.model.MethodDefinition;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
|
@ -56,6 +57,17 @@ public class RestMethodMetadata implements Serializable {
|
|||
|
||||
private Map<Integer, Boolean> indexToEncoded;
|
||||
|
||||
private ServiceRestMetadata serviceRestMetadata;
|
||||
|
||||
private List<ArgInfo> argInfos;
|
||||
|
||||
private Method reflectMethod;
|
||||
|
||||
/**
|
||||
* make a distinction between mvc & resteasy
|
||||
*/
|
||||
private Class codeStyle;
|
||||
|
||||
public MethodDefinition getMethod() {
|
||||
if (method == null) {
|
||||
method = new MethodDefinition();
|
||||
|
|
@ -112,7 +124,7 @@ public class RestMethodMetadata implements Serializable {
|
|||
|
||||
public Map<Integer, Collection<String>> getIndexToName() {
|
||||
if (indexToName == null) {
|
||||
indexToName = new HashMap<>();
|
||||
indexToName = new LinkedHashMap<>();
|
||||
}
|
||||
return indexToName;
|
||||
}
|
||||
|
|
@ -157,6 +169,43 @@ public class RestMethodMetadata implements Serializable {
|
|||
this.indexToEncoded = indexToEncoded;
|
||||
}
|
||||
|
||||
|
||||
public ServiceRestMetadata getServiceRestMetadata() {
|
||||
return serviceRestMetadata;
|
||||
}
|
||||
|
||||
public void setServiceRestMetadata(ServiceRestMetadata serviceRestMetadata) {
|
||||
this.serviceRestMetadata = serviceRestMetadata;
|
||||
}
|
||||
|
||||
public List<ArgInfo> getArgInfos() {
|
||||
if (argInfos == null) {
|
||||
argInfos = new ArrayList<>();
|
||||
}
|
||||
return argInfos;
|
||||
}
|
||||
|
||||
public void addArgInfo(ArgInfo argInfo) {
|
||||
getArgInfos().add(argInfo);
|
||||
}
|
||||
|
||||
|
||||
public Method getReflectMethod() {
|
||||
return reflectMethod;
|
||||
}
|
||||
|
||||
public void setReflectMethod(Method reflectMethod) {
|
||||
this.reflectMethod = reflectMethod;
|
||||
}
|
||||
|
||||
public Class getCodeStyle() {
|
||||
return codeStyle;
|
||||
}
|
||||
|
||||
public void setCodeStyle(Class codeStyle) {
|
||||
this.codeStyle = codeStyle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
|
@ -167,13 +216,13 @@ public class RestMethodMetadata implements Serializable {
|
|||
}
|
||||
RestMethodMetadata that = (RestMethodMetadata) o;
|
||||
return Objects.equals(getMethod(), that.getMethod()) &&
|
||||
Objects.equals(getRequest(), that.getRequest()) &&
|
||||
Objects.equals(getUrlIndex(), that.getUrlIndex()) &&
|
||||
Objects.equals(getBodyIndex(), that.getBodyIndex()) &&
|
||||
Objects.equals(getHeaderMapIndex(), that.getHeaderMapIndex()) &&
|
||||
Objects.equals(getBodyType(), that.getBodyType()) &&
|
||||
Objects.equals(getFormParams(), that.getFormParams()) &&
|
||||
Objects.equals(getIndexToEncoded(), that.getIndexToEncoded());
|
||||
Objects.equals(getRequest(), that.getRequest()) &&
|
||||
Objects.equals(getUrlIndex(), that.getUrlIndex()) &&
|
||||
Objects.equals(getBodyIndex(), that.getBodyIndex()) &&
|
||||
Objects.equals(getHeaderMapIndex(), that.getHeaderMapIndex()) &&
|
||||
Objects.equals(getBodyType(), that.getBodyType()) &&
|
||||
Objects.equals(getFormParams(), that.getFormParams()) &&
|
||||
Objects.equals(getIndexToEncoded(), that.getIndexToEncoded());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -16,8 +16,12 @@
|
|||
*/
|
||||
package org.apache.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.metadata.ParameterTypesComparator;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -39,6 +43,32 @@ public class ServiceRestMetadata implements Serializable {
|
|||
|
||||
private Set<RestMethodMetadata> meta;
|
||||
|
||||
private Integer port;
|
||||
|
||||
private boolean consumer;
|
||||
|
||||
/**
|
||||
* make a distinction between mvc & resteasy
|
||||
*/
|
||||
private Class codeStyle;
|
||||
|
||||
private Map<PathMatcher, RestMethodMetadata> pathToServiceMap = new HashMap<>();
|
||||
private Map<String, Map<ParameterTypesComparator, RestMethodMetadata>> methodToServiceMap = new HashMap<>();
|
||||
|
||||
public ServiceRestMetadata(String serviceInterface, String version, String group, boolean consumer) {
|
||||
this.serviceInterface = serviceInterface;
|
||||
this.version = version;
|
||||
this.group = group;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public ServiceRestMetadata() {
|
||||
}
|
||||
|
||||
public ServiceRestMetadata(String serviceInterface, String version, String group) {
|
||||
this(serviceInterface, version, group, false);
|
||||
}
|
||||
|
||||
public String getServiceInterface() {
|
||||
return serviceInterface;
|
||||
}
|
||||
|
|
@ -74,6 +104,70 @@ public class ServiceRestMetadata implements Serializable {
|
|||
this.meta = meta;
|
||||
}
|
||||
|
||||
public void addRestMethodMetadata(RestMethodMetadata restMethodMetadata) {
|
||||
restMethodMetadata.setServiceRestMetadata(this);
|
||||
PathMatcher pathMather = new PathMatcher(restMethodMetadata.getRequest().getPath(),
|
||||
this.getVersion(), this.getGroup(), this.getPort());
|
||||
addPathToServiceMap(pathMather, restMethodMetadata);
|
||||
addMethodToServiceMap(restMethodMetadata);
|
||||
getMeta().add(restMethodMetadata);
|
||||
}
|
||||
|
||||
public Map<PathMatcher, RestMethodMetadata> getPathToServiceMap() {
|
||||
return pathToServiceMap;
|
||||
}
|
||||
|
||||
public void addPathToServiceMap(PathMatcher pathMather, RestMethodMetadata restMethodMetadata) {
|
||||
if (this.pathToServiceMap == null) {
|
||||
this.pathToServiceMap = new HashMap<>();
|
||||
}
|
||||
|
||||
this.pathToServiceMap.put(pathMather, restMethodMetadata);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
Map<PathMatcher, RestMethodMetadata> pathToServiceMap = getPathToServiceMap();
|
||||
for (PathMatcher pathMather : pathToServiceMap.keySet()) {
|
||||
pathMather.setPort(port);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConsumer() {
|
||||
return consumer;
|
||||
}
|
||||
|
||||
public void setConsumer(boolean consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public Map<String, Map<ParameterTypesComparator, RestMethodMetadata>> getMethodToServiceMap() {
|
||||
return methodToServiceMap;
|
||||
}
|
||||
|
||||
public void addMethodToServiceMap(RestMethodMetadata restMethodMetadata) {
|
||||
if (this.methodToServiceMap == null) {
|
||||
this.methodToServiceMap = new HashMap<>();
|
||||
}
|
||||
|
||||
this.methodToServiceMap.computeIfAbsent(restMethodMetadata.getReflectMethod().getName(), k -> new HashMap<>())
|
||||
.put(ParameterTypesComparator.getInstance(restMethodMetadata.getReflectMethod().getParameterTypes()), restMethodMetadata);
|
||||
}
|
||||
|
||||
public Class getCodeStyle() {
|
||||
return codeStyle;
|
||||
}
|
||||
|
||||
public void setCodeStyle(Class codeStyle) {
|
||||
this.codeStyle = codeStyle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
|
@ -84,14 +178,15 @@ public class ServiceRestMetadata implements Serializable {
|
|||
}
|
||||
ServiceRestMetadata that = (ServiceRestMetadata) o;
|
||||
return Objects.equals(getServiceInterface(), that.getServiceInterface()) &&
|
||||
Objects.equals(getVersion(), that.getVersion()) &&
|
||||
Objects.equals(getGroup(), that.getGroup()) &&
|
||||
Objects.equals(getMeta(), that.getMeta());
|
||||
Objects.equals(getVersion(), that.getVersion()) &&
|
||||
Objects.equals(getGroup(), that.getGroup()) &&
|
||||
Objects.equals(getMeta(), that.getMeta()) &&
|
||||
Objects.equals(getPort(), that.getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getServiceInterface(), getVersion(), getGroup(), getMeta());
|
||||
return Objects.hash(getServiceInterface(), getVersion(), getGroup(), getMeta(), getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -101,6 +196,7 @@ public class ServiceRestMetadata implements Serializable {
|
|||
sb.append(", version='").append(version).append('\'');
|
||||
sb.append(", group='").append(group).append('\'');
|
||||
sb.append(", meta=").append(meta);
|
||||
sb.append(", port=").append(port);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.metadata.rest;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
/**
|
||||
|
|
@ -24,7 +25,7 @@ import org.apache.dubbo.common.extension.SPI;
|
|||
*
|
||||
* @since 2.7.6
|
||||
*/
|
||||
@SPI
|
||||
@SPI(scope = ExtensionScope.APPLICATION)
|
||||
public interface ServiceRestMetadataResolver {
|
||||
|
||||
/**
|
||||
|
|
@ -35,6 +36,8 @@ public interface ServiceRestMetadataResolver {
|
|||
*/
|
||||
boolean supports(Class<?> serviceType);
|
||||
|
||||
boolean supports(Class<?> serviceType,boolean consumer);
|
||||
|
||||
/**
|
||||
* Resolve the {@link ServiceRestMetadata REST metadata} from the specified
|
||||
* Dubbo Service interface or type
|
||||
|
|
@ -43,4 +46,6 @@ public interface ServiceRestMetadataResolver {
|
|||
* @return
|
||||
*/
|
||||
ServiceRestMetadata resolve(Class<?> serviceType);
|
||||
|
||||
ServiceRestMetadata resolve(Class<?> serviceType, ServiceRestMetadata serviceRestMetadata);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest;
|
||||
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
|
||||
import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
|
||||
|
||||
public interface SpringMvcClassConstants extends RestMetadataConstants.SPRING_MVC {
|
||||
/**
|
||||
* The annotation class of @RequestMapping
|
||||
*/
|
||||
Class REQUEST_MAPPING_ANNOTATION_CLASS = resolveClass(REQUEST_MAPPING_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @RequestHeader
|
||||
*/
|
||||
Class REQUEST_HEADER_ANNOTATION_CLASS = resolveClass(REQUEST_HEADER_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @RequestParam
|
||||
*/
|
||||
Class REQUEST_PARAM_ANNOTATION_CLASS = resolveClass(REQUEST_PARAM_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @RequestBody
|
||||
*/
|
||||
Class REQUEST_BODY_ANNOTATION_CLASS = resolveClass(REQUEST_BODY_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
|
||||
|
||||
/**
|
||||
* The annotation class of @RequestBody
|
||||
*/
|
||||
Class PATH_VARIABLE_ANNOTATION_CLASS= resolveClass(PATH_VARIABLE_ANNOTATION_CLASS_NAME, getClassLoader());
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.jaxrs;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.ArgInfo;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.REST_EASY_BODY_ANNOTATION_CLASS_NAME;
|
||||
|
||||
/**
|
||||
* The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @FormParam
|
||||
*
|
||||
* @since 2.7.6
|
||||
*/
|
||||
public class BodyParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationName() {
|
||||
return REST_EASY_BODY_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Annotation annotation, Parameter parameter, int parameterIndex, Method method, Class<?> serviceType, Class<?> serviceInterfaceClass, RestMethodMetadata restMethodMetadata) {
|
||||
ArgInfo argInfo = ArgInfo.
|
||||
build(parameterIndex, parameter).
|
||||
setParamAnnotationType(getAnnotationClass());
|
||||
restMethodMetadata.addArgInfo(argInfo);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -38,12 +39,12 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.DEFAUL
|
|||
public class DefaultValueParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return DEFAULT_VALUE_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(String annotationValue, String defaultValue, Annotation annotation, Object parameter,
|
||||
protected void process(String annotationValue, String defaultValue, Annotation annotation, Parameter parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) {
|
||||
RequestMetadata requestMetadata = restMethodMetadata.getRequest();
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.FORM_P
|
|||
public class FormParamParameterProcessor extends ParamAnnotationParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return FORM_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor.buildDefaultValue;
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HEADER_PARAM_ANNOTATION_CLASS_NAME;
|
||||
|
|
@ -35,12 +36,12 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.HEADER
|
|||
public class HeaderParamParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return HEADER_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(String headerName, String defaultValue, Annotation annotation, Object parameter,
|
||||
protected void process(String headerName, String defaultValue, Annotation annotation, Parameter parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) {
|
||||
RequestMetadata requestMetadata = restMethodMetadata.getRequest();
|
||||
// Add the placeholder as header value
|
||||
|
|
|
|||
|
|
@ -85,12 +85,16 @@ public class JAXRSServiceRestMetadataResolver extends AbstractServiceRestMetadat
|
|||
protected void processProduces(Method serviceMethod, Class<?> serviceType, Class<?> serviceInterfaceClass,
|
||||
Set<String> produces) {
|
||||
addAnnotationValues(serviceMethod, PRODUCES_ANNOTATION_CLASS_NAME, produces);
|
||||
addAnnotationValues(serviceType, PRODUCES_ANNOTATION_CLASS_NAME, produces);
|
||||
addAnnotationValues(serviceInterfaceClass, PRODUCES_ANNOTATION_CLASS_NAME, produces);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processConsumes(Method serviceMethod, Class<?> serviceType, Class<?> serviceInterfaceClass,
|
||||
Set<String> consumes) {
|
||||
addAnnotationValues(serviceMethod, CONSUMES_ANNOTATION_CLASS_NAME, consumes);
|
||||
addAnnotationValues(serviceType, CONSUMES_ANNOTATION_CLASS_NAME, consumes);
|
||||
addAnnotationValues(serviceInterfaceClass, CONSUMES_ANNOTATION_CLASS_NAME, consumes);
|
||||
}
|
||||
|
||||
private void addAnnotationValues(Method serviceMethod, String annotationAttributeName, Set<String> result) {
|
||||
|
|
@ -100,4 +104,12 @@ public class JAXRSServiceRestMetadataResolver extends AbstractServiceRestMetadat
|
|||
Stream.of(value).forEach(result::add);
|
||||
}
|
||||
}
|
||||
|
||||
private void addAnnotationValues(Class serviceType, String annotationAttributeName, Set<String> result) {
|
||||
Annotation annotation = findAnnotation(serviceType, annotationAttributeName);
|
||||
String[] value = getValue(annotation);
|
||||
if (value != null) {
|
||||
Stream.of(value).forEach(result::add);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.MATRIX
|
|||
public class MatrixParamParameterProcessor extends ParamAnnotationParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return MATRIX_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
/**
|
||||
* The abstract {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @*Param
|
||||
|
|
@ -30,7 +31,7 @@ import java.lang.reflect.Method;
|
|||
public abstract class ParamAnnotationParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Object parameter,
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Parameter parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) {
|
||||
RequestMetadata requestMetadata = restMethodMetadata.getRequest();
|
||||
requestMetadata.addParam(name, defaultValue);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.jaxrs;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.PATH_PARAM_ANNOTATION_CLASS_NAME;
|
||||
|
||||
/**
|
||||
* The {@link AnnotatedMethodParameterProcessor} implementation for JAX-RS's @PathParam
|
||||
*
|
||||
* @since 2.7.6
|
||||
*/
|
||||
public class PathParamParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationName() {
|
||||
return PATH_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.JAX_RS.QUERY_
|
|||
public class QueryParamParameterProcessor extends ParamAnnotationParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return QUERY_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.media;
|
||||
|
||||
|
||||
public enum MediaType {
|
||||
ALL_VALUE("*/*"),
|
||||
APPLICATION_JSON_VALUE("application/json"),
|
||||
APPLICATION_FORM_URLENCODED_VALUE("application/x-www-form-urlencoded"),
|
||||
TEXT_PLAIN("text/plain"),
|
||||
TEXT_XML("text/xml"),
|
||||
OCTET_STREAM("application/octet-stream"),
|
||||
;
|
||||
|
||||
MediaType(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value;
|
||||
|
||||
public static String getAllContentType() {
|
||||
|
||||
MediaType[] values = MediaType.values();
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
for (MediaType mediaType : values) {
|
||||
stringBuilder.append(mediaType.value + " ");
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractNoAnnotatedParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
import static org.apache.dubbo.metadata.rest.media.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
|
||||
|
||||
public class FormBodyNoAnnotatedProcessor extends AbstractNoAnnotatedParameterProcessor {
|
||||
@Override
|
||||
public MediaType consumerContentType() {
|
||||
return APPLICATION_FORM_URLENCODED_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultAnnotationClassName(RestMethodMetadata restMethodMetadata) {
|
||||
return REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFormContentType(RestMethodMetadata restMethodMetadata) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractNoAnnotatedParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
import static org.apache.dubbo.metadata.rest.media.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
public class JsonBodyNoAnnotatedProcessor extends AbstractNoAnnotatedParameterProcessor {
|
||||
@Override
|
||||
public MediaType consumerContentType() {
|
||||
return APPLICATION_JSON_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultAnnotationClassName(RestMethodMetadata restMethodMetadata) {
|
||||
return REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractNoAnnotatedParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver;
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
import org.apache.dubbo.metadata.rest.tag.BodyTag;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_PARAM_ANNOTATION_CLASS_NAME;
|
||||
import static org.apache.dubbo.metadata.rest.media.MediaType.ALL_VALUE;
|
||||
|
||||
public class ParamNoAnnotatedProcessor extends AbstractNoAnnotatedParameterProcessor {
|
||||
@Override
|
||||
public MediaType consumerContentType() {
|
||||
return ALL_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultAnnotationClassName(RestMethodMetadata restMethodMetadata) {
|
||||
|
||||
if (JAXRSServiceRestMetadataResolver.class.equals(restMethodMetadata.getCodeStyle())) {
|
||||
return BodyTag.class.getName();
|
||||
}
|
||||
|
||||
return REQUEST_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.PATH_VARIABLE_ANNOTATION_CLASS_NAME;
|
||||
|
||||
/**
|
||||
* The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @PathVariable
|
||||
*/
|
||||
public class PathVariableParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationName() {
|
||||
return PATH_VARIABLE_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultValue(Annotation annotation, Parameter parameter, int parameterIndex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.AbstractAnnotatedMethodParameterProcessor;
|
||||
import org.apache.dubbo.metadata.rest.AnnotatedMethodParameterProcessor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
|
||||
/**
|
||||
* The {@link AnnotatedMethodParameterProcessor} implementation for Spring Web MVC's @RequestBody
|
||||
*/
|
||||
public class RequestBodyParameterProcessor extends AbstractAnnotatedMethodParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationName() {
|
||||
return REQUEST_BODY_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getAnnotationValue(Annotation annotation, Parameter parameter, int parameterIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultValue(Annotation annotation, Parameter parameter, int parameterIndex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_HEADER_ANNOTATION_CLASS_NAME;
|
||||
|
||||
|
|
@ -30,12 +31,12 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.RE
|
|||
public class RequestHeaderParameterProcessor extends AbstractRequestAnnotationParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return REQUEST_HEADER_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Object parameter,
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Parameter parameter,
|
||||
int parameterIndex, Method method, RestMethodMetadata restMethodMetadata) {
|
||||
restMethodMetadata.getRequest().addHeader(name, defaultValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_PARAM_ANNOTATION_CLASS_NAME;
|
||||
|
||||
|
|
@ -30,14 +31,13 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.RE
|
|||
public class RequestParamParameterProcessor extends AbstractRequestAnnotationParameterProcessor {
|
||||
|
||||
@Override
|
||||
public String getAnnotationType() {
|
||||
public String getAnnotationName() {
|
||||
return REQUEST_PARAM_ANNOTATION_CLASS_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Object parameter, int parameterIndex,
|
||||
protected void process(String name, String defaultValue, Annotation annotation, Parameter parameter, int parameterIndex,
|
||||
Method method, RestMethodMetadata restMethodMetadata) {
|
||||
restMethodMetadata.getRequest().addParam(name, defaultValue);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,11 +89,15 @@ public class SpringMvcServiceRestMetadataResolver extends AbstractServiceRestMet
|
|||
@Override
|
||||
protected void processProduces(Method serviceMethod, Class<?> serviceType, Class<?> serviceInterfaceClass, Set<String> produces) {
|
||||
addMediaTypes(serviceMethod, "produces", produces);
|
||||
addMediaTypes(serviceType, "produces", produces);
|
||||
addMediaTypes(serviceInterfaceClass, "produces", produces);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processConsumes(Method serviceMethod, Class<?> serviceType, Class<?> serviceInterfaceClass, Set<String> consumes) {
|
||||
addMediaTypes(serviceMethod, "consumes", consumes);
|
||||
addMediaTypes(serviceType, "consumes", consumes);
|
||||
addMediaTypes(serviceInterfaceClass, "consumes", consumes);
|
||||
}
|
||||
|
||||
private String resolveRequestPath(AnnotatedElement annotatedElement) {
|
||||
|
|
@ -124,6 +128,17 @@ public class SpringMvcServiceRestMetadataResolver extends AbstractServiceRestMet
|
|||
}
|
||||
}
|
||||
|
||||
private void addMediaTypes(Class serviceType, String annotationAttributeName, Set<String> mediaTypesSet) {
|
||||
|
||||
Annotation mappingAnnotation = getRequestMapping(serviceType);
|
||||
|
||||
String[] mediaTypes = getAttribute(mappingAnnotation, annotationAttributeName);
|
||||
|
||||
if (isNotEmpty(mediaTypes)) {
|
||||
of(mediaTypes).forEach(mediaTypesSet::add);
|
||||
}
|
||||
}
|
||||
|
||||
private Annotation getRequestMapping(AnnotatedElement annotatedElement) {
|
||||
// try "@RequestMapping" first
|
||||
Annotation requestMapping = findAnnotation(annotatedElement, REQUEST_MAPPING_ANNOTATION_CLASS);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.tag;
|
||||
|
||||
public class BodyTag {
|
||||
}
|
||||
|
|
@ -4,7 +4,11 @@ jax-rs.form-param = org.apache.dubbo.metadata.rest.jaxrs.FormParamParameterProce
|
|||
jax-rs.matrix-param = org.apache.dubbo.metadata.rest.jaxrs.MatrixParamParameterProcessor
|
||||
jax-rs.header-param = org.apache.dubbo.metadata.rest.jaxrs.HeaderParamParameterProcessor
|
||||
jax-rs.default-value-param = org.apache.dubbo.metadata.rest.jaxrs.DefaultValueParameterProcessor
|
||||
jax-rs.body = org.apache.dubbo.metadata.rest.jaxrs.BodyParameterProcessor
|
||||
jax-rs.path-param = org.apache.dubbo.metadata.rest.jaxrs.PathParamParameterProcessor
|
||||
|
||||
# Spring Web MVC's implementations
|
||||
spring-webmvc.request-param = org.apache.dubbo.metadata.rest.springmvc.RequestParamParameterProcessor
|
||||
spring-webmvc.request-header = org.apache.dubbo.metadata.rest.springmvc.RequestHeaderParameterProcessor
|
||||
spring-webmvc.request-header = org.apache.dubbo.metadata.rest.springmvc.RequestHeaderParameterProcessor
|
||||
spring-webmvc.request-body = org.apache.dubbo.metadata.rest.springmvc.RequestBodyParameterProcessor
|
||||
spring-webmvc.request-path = org.apache.dubbo.metadata.rest.springmvc.PathVariableParameterProcessor
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
body-form=org.apache.dubbo.metadata.rest.springmvc.FormBodyNoAnnotatedProcessor
|
||||
body-json=org.apache.dubbo.metadata.rest.springmvc.JsonBodyNoAnnotatedProcessor
|
||||
param=org.apache.dubbo.metadata.rest.springmvc.ParamNoAnnotatedProcessor
|
||||
|
|
@ -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.dubbo.metadata;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.PathMatcher;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PathMatcherTest {
|
||||
|
||||
@Test
|
||||
public void testPathMatcher() {
|
||||
PathMatcher pathMather = new PathMatcher("/a/b/c/{path1}/d/{path2}/e");
|
||||
|
||||
PathMatcher pathMather1 = new PathMatcher("/a/b/c/1/d/2/e");
|
||||
Assertions.assertEquals(true, pathMather.equals(pathMather1));
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +63,21 @@ public class DefaultRestService implements RestService {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noAnnotationJsonBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noAnnotationFormBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noAnnotationParam(String text) {
|
||||
|
||||
}
|
||||
|
||||
public User user(User user) {
|
||||
return user;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@ public interface RestService {
|
|||
User requestBodyMap(Map<String, Object> data, String param);
|
||||
|
||||
Map<String, Object> requestBodyUser(User user);
|
||||
|
||||
void noAnnotationJsonBody(User user);
|
||||
void noAnnotationFormBody(User user);
|
||||
void noAnnotationParam(String text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ package org.apache.dubbo.metadata.rest;
|
|||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -92,4 +92,22 @@ public class SpringRestService implements RestService {
|
|||
map.put("age", user.getAge());
|
||||
return map;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/request/body/user/json", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
@Override
|
||||
public void noAnnotationJsonBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@PostMapping(value = "/request/body/user/form", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@Override
|
||||
public void noAnnotationFormBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@PostMapping(value = "/request/body/user/param")
|
||||
@Override
|
||||
public void noAnnotationParam(String text) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -104,4 +105,27 @@ public class StandardRestService implements RestService {
|
|||
map.put("age", user.getAge());
|
||||
return map;
|
||||
}
|
||||
|
||||
@Path("noAnnotationJsonBody/json")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Override
|
||||
public void noAnnotationJsonBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@Path("noAnnotationFormBody/form")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@POST
|
||||
@Override
|
||||
public void noAnnotationFormBody(User user) {
|
||||
|
||||
}
|
||||
|
||||
@Path("noAnnotationParam/text")
|
||||
@POST
|
||||
@Override
|
||||
public void noAnnotationParam(String text) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.api;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.User;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("u")
|
||||
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
|
||||
@Produces({MediaType.APPLICATION_JSON})
|
||||
public interface AnotherUserRestService {
|
||||
|
||||
@GET
|
||||
@Path("{id : \\d+}")
|
||||
User getUser(@PathParam("id") Long id);
|
||||
|
||||
@POST
|
||||
@Path("register")
|
||||
String registerUser(User user);
|
||||
|
||||
@GET
|
||||
@Path("context")
|
||||
String getContext();
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.api;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.User;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
public interface JaxrsRestService {
|
||||
|
||||
@Path("/param")
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@GET
|
||||
String param(@QueryParam("param") String param);
|
||||
|
||||
@Path("/header")
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@GET
|
||||
String header(@HeaderParam("header") String header);
|
||||
|
||||
@Path("/body")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@POST
|
||||
User body(User user);
|
||||
|
||||
@Path("/multiValue")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@POST
|
||||
MultivaluedMap multiValue(MultivaluedMap map);
|
||||
|
||||
@Path("/pathVariable/{a}")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@POST
|
||||
String pathVariable(@PathParam("a") String a);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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.dubbo.metadata.rest.api;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.User;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
public class JaxrsRestServiceImpl implements JaxrsRestService {
|
||||
|
||||
|
||||
@Override
|
||||
public String param(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User body(User user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultivaluedMap multiValue(MultivaluedMap map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String pathVariable(String a) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.api;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.User;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
|
||||
@RestController
|
||||
public interface SpringRestService {
|
||||
|
||||
|
||||
@RequestMapping(value = "/param", method = RequestMethod.GET, consumes = MediaType.TEXT_PLAIN_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
String param(@RequestParam("param") String param);
|
||||
|
||||
@RequestMapping(value = "/header", method = RequestMethod.GET, consumes = MediaType.TEXT_PLAIN_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
String header(@RequestHeader("header") String header);
|
||||
|
||||
@RequestMapping(value = "/header", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User body(@RequestBody User user);
|
||||
|
||||
@RequestMapping(value = "/multiValue", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
MultiValueMap multiValue(@RequestBody MultiValueMap map);
|
||||
|
||||
|
||||
@RequestMapping(value = "/pathVariable/{a}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
String pathVariable(@PathVariable String a);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.dubbo.metadata.rest.api;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.User;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@RestController
|
||||
public class SpringRestServiceImpl implements SpringRestService {
|
||||
|
||||
|
||||
@Override
|
||||
public String param(String param) {
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String header(String header) {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User body(User user) {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap multiValue(MultiValueMap map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String pathVariable(String a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,16 +17,27 @@
|
|||
package org.apache.dubbo.metadata.rest.jaxrs;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.JsonUtils;
|
||||
import org.apache.dubbo.metadata.rest.ClassPathServiceRestMetadataReader;
|
||||
import org.apache.dubbo.metadata.rest.DefaultRestService;
|
||||
import org.apache.dubbo.metadata.rest.PathUtil;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.RestService;
|
||||
import org.apache.dubbo.metadata.rest.ServiceRestMetadata;
|
||||
import org.apache.dubbo.metadata.rest.SpringRestService;
|
||||
import org.apache.dubbo.metadata.rest.StandardRestService;
|
||||
import org.apache.dubbo.metadata.rest.api.AnotherUserRestService;
|
||||
import org.apache.dubbo.metadata.rest.api.JaxrsRestService;
|
||||
import org.apache.dubbo.metadata.rest.api.JaxrsRestServiceImpl;
|
||||
import org.apache.dubbo.metadata.rest.api.SpringRestService;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
|
@ -42,6 +53,7 @@ class JAXRSServiceRestMetadataResolverTest {
|
|||
|
||||
private JAXRSServiceRestMetadataResolver instance = new JAXRSServiceRestMetadataResolver(ApplicationModel.defaultModel());
|
||||
|
||||
|
||||
@Test
|
||||
void testSupports() {
|
||||
// JAX-RS RestService class
|
||||
|
|
@ -57,6 +69,7 @@ class JAXRSServiceRestMetadataResolverTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testResolve() {
|
||||
// Generated by "dubbo-metadata-processor"
|
||||
ClassPathServiceRestMetadataReader reader = new ClassPathServiceRestMetadataReader("META-INF/dubbo/jax-rs-service-rest-metadata.json");
|
||||
|
|
@ -70,4 +83,75 @@ class JAXRSServiceRestMetadataResolverTest {
|
|||
assertEquals(expectedServiceRestMetadata, serviceRestMetadata);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolves() {
|
||||
testResolve(JaxrsRestService.class);
|
||||
testResolve(JaxrsRestServiceImpl.class);
|
||||
}
|
||||
|
||||
|
||||
void testResolve(Class service) {
|
||||
// Generated by "dubbo-metadata-processor"
|
||||
|
||||
List<String> jsons = Arrays.asList(
|
||||
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"a\",\"defaultValue\":\"{0}\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"javax.ws.rs.PathParam\",\"paramName\":\"a\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":2}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver\",\"indexToName\":{0:[\"a\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/x-www-form-urlencoded\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/pathVariable/{a}\",\"produces\":[\"application/x-www-form-urlencoded\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"map\",\"formContentType\":true,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestBody\",\"paramName\":\"map\",\"paramType\":\"javax.ws.rs.core.MultivaluedMap\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver\",\"indexToName\":{0:[\"map\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/x-www-form-urlencoded\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/multiValue\",\"produces\":[\"application/x-www-form-urlencoded\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"user\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestBody\",\"paramName\":\"user\",\"paramType\":\"org.apache.dubbo.metadata.rest.User\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver\",\"indexToName\":{0:[\"user\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/json\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/body\",\"produces\":[\"application/json\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"param\",\"defaultValue\":\"{0}\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"javax.ws.rs.QueryParam\",\"paramName\":\"param\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver\",\"indexToName\":{0:[\"param\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"text/plain\"],\"headerNames\":[],\"headers\":{},\"method\":\"GET\",\"paramNames\":[\"param\"],\"params\":{\"param\":[\"{0}\"]},\"path\":\"/param\",\"produces\":[\"text/plain\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"header\",\"defaultValue\":\"{0}\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"javax.ws.rs.HeaderParam\",\"paramName\":\"header\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver\",\"indexToName\":{0:[\"header\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"text/plain\"],\"headerNames\":[\"header\"],\"headers\":{\"header\":[\"{0}\"]},\"method\":\"GET\",\"paramNames\":[],\"params\":{},\"path\":\"/header\",\"produces\":[\"text/plain\"]}}"
|
||||
|
||||
|
||||
);
|
||||
|
||||
ServiceRestMetadata jaxrsRestMetadata = new ServiceRestMetadata();
|
||||
jaxrsRestMetadata.setServiceInterface(service.getName());
|
||||
ServiceRestMetadata jaxrsMetadata = instance.resolve(service, jaxrsRestMetadata);
|
||||
|
||||
|
||||
List<String> jsonsTmp = new ArrayList<>();
|
||||
for (RestMethodMetadata restMethodMetadata : jaxrsMetadata.getMeta()) {
|
||||
restMethodMetadata.setServiceRestMetadata(null);
|
||||
restMethodMetadata.setReflectMethod(null);
|
||||
restMethodMetadata.setMethod(null);
|
||||
jsonsTmp.add(JsonUtils.getJson().toJson(restMethodMetadata));
|
||||
}
|
||||
|
||||
Comparator<String> comparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return o1.length() - o2.length();
|
||||
}
|
||||
};
|
||||
jsons.sort(comparator);
|
||||
jsonsTmp.sort(comparator);
|
||||
|
||||
|
||||
for (int i = 0; i < jsons.size(); i++) {
|
||||
assertEquals(jsons.get(i), jsonsTmp.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testJaxrsPathPattern() {
|
||||
Class service = AnotherUserRestService.class;
|
||||
ServiceRestMetadata jaxrsRestMetadata = new ServiceRestMetadata();
|
||||
jaxrsRestMetadata.setServiceInterface(service.getName());
|
||||
ServiceRestMetadata jaxrsMetadata = instance.resolve(service, jaxrsRestMetadata);
|
||||
|
||||
RestMethodMetadata[] objects = jaxrsMetadata.getMeta().toArray(new RestMethodMetadata[0]);
|
||||
RestMethodMetadata object = null;
|
||||
for (RestMethodMetadata obj : objects) {
|
||||
if ("getUser".equals(obj.getReflectMethod().getName())) {
|
||||
object = obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Assertions.assertEquals("/u/1", PathUtil.resolvePathVariable("u/{id : \\d+}", object.getArgInfos(), Arrays.asList(1)));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,23 @@
|
|||
package org.apache.dubbo.metadata.rest.springmvc;
|
||||
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.JsonUtils;
|
||||
import org.apache.dubbo.metadata.rest.ClassPathServiceRestMetadataReader;
|
||||
import org.apache.dubbo.metadata.rest.DefaultRestService;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.RestService;
|
||||
import org.apache.dubbo.metadata.rest.ServiceRestMetadata;
|
||||
import org.apache.dubbo.metadata.rest.SpringRestService;
|
||||
import org.apache.dubbo.metadata.rest.StandardRestService;
|
||||
import org.apache.dubbo.metadata.rest.api.SpringRestService;
|
||||
import org.apache.dubbo.metadata.rest.api.SpringRestServiceImpl;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
|
@ -45,18 +52,19 @@ class SpringMvcServiceRestMetadataResolverTest {
|
|||
@Test
|
||||
void testSupports() {
|
||||
// Spring MVC RestService class
|
||||
assertTrue(instance.supports(SpringRestService.class));
|
||||
assertTrue(instance.supports(SpringRestService.class, true));
|
||||
// JAX-RS RestService class
|
||||
assertFalse(instance.supports(StandardRestService.class));
|
||||
assertFalse(instance.supports(StandardRestService.class, true));
|
||||
// Default RestService class
|
||||
assertFalse(instance.supports(DefaultRestService.class));
|
||||
assertFalse(instance.supports(DefaultRestService.class, true));
|
||||
// No annotated RestService class
|
||||
assertFalse(instance.supports(RestService.class));
|
||||
assertFalse(instance.supports(RestService.class, true));
|
||||
// null
|
||||
assertFalse(instance.supports(null));
|
||||
assertFalse(instance.supports(null, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
void testResolve() {
|
||||
// Generated by "dubbo-metadata-processor"
|
||||
ClassPathServiceRestMetadataReader reader = new ClassPathServiceRestMetadataReader("META-INF/dubbo/spring-mvc-service-rest-metadata.json");
|
||||
|
|
@ -70,4 +78,51 @@ class SpringMvcServiceRestMetadataResolverTest {
|
|||
assertEquals(expectedServiceRestMetadata, serviceRestMetadata);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResolves() {
|
||||
testResolve(SpringRestService.class);
|
||||
testResolve(SpringRestServiceImpl.class);
|
||||
}
|
||||
|
||||
void testResolve(Class service) {
|
||||
List<String> jsons = Arrays.asList(
|
||||
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.PathVariable\",\"paramName\":\"a\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":2}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver\",\"indexToName\":{0:[\"a\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/x-www-form-urlencoded\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/pathVariable/{a}\",\"produces\":[\"application/x-www-form-urlencoded\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"user\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestBody\",\"paramName\":\"user\",\"paramType\":\"org.apache.dubbo.metadata.rest.User\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver\",\"indexToName\":{0:[\"user\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/json\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/header\",\"produces\":[\"application/json\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"param\",\"defaultValue\":\"{0}\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestParam\",\"paramName\":\"param\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver\",\"indexToName\":{0:[\"param\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"text/plain\"],\"headerNames\":[],\"headers\":{},\"method\":\"GET\",\"paramNames\":[\"param\"],\"params\":{\"param\":[\"{0}\"]},\"path\":\"/param\",\"produces\":[\"text/plain\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"map\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestBody\",\"paramName\":\"map\",\"paramType\":\"org.springframework.util.MultiValueMap\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver\",\"indexToName\":{0:[\"map\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"application/x-www-form-urlencoded\"],\"headerNames\":[],\"headers\":{},\"method\":\"POST\",\"paramNames\":[],\"params\":{},\"path\":\"/multiValue\",\"produces\":[\"application/x-www-form-urlencoded\"]}}",
|
||||
"{\"argInfos\":[{\"annotationNameAttribute\":\"header\",\"defaultValue\":\"{0}\",\"formContentType\":false,\"index\":0,\"paramAnnotationType\":\"org.springframework.web.bind.annotation.RequestHeader\",\"paramName\":\"header\",\"paramType\":\"java.lang.String\",\"urlSplitIndex\":0}],\"codeStyle\":\"org.apache.dubbo.metadata.rest.springmvc.SpringMvcServiceRestMetadataResolver\",\"indexToName\":{0:[\"header\"]},\"method\":{\"annotations\":[],\"parameters\":[]},\"request\":{\"consumes\":[\"text/plain\"],\"headerNames\":[\"header\"],\"headers\":{\"header\":[\"{0}\"]},\"method\":\"GET\",\"paramNames\":[],\"params\":{},\"path\":\"/header\",\"produces\":[\"text/plain\"]}}"
|
||||
|
||||
|
||||
);
|
||||
|
||||
ServiceRestMetadata springRestMetadata = new ServiceRestMetadata();
|
||||
springRestMetadata.setServiceInterface(service.getName());
|
||||
ServiceRestMetadata springMetadata = instance.resolve(service, springRestMetadata);
|
||||
|
||||
|
||||
List<String> jsonsTmp = new ArrayList<>();
|
||||
for (RestMethodMetadata restMethodMetadata : springMetadata.getMeta()) {
|
||||
restMethodMetadata.setServiceRestMetadata(null);
|
||||
restMethodMetadata.setReflectMethod(null);
|
||||
restMethodMetadata.setMethod(null);
|
||||
jsonsTmp.add(JsonUtils.getJson().toJson(restMethodMetadata));
|
||||
}
|
||||
|
||||
Comparator<String> comparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return o1.length() - o2.length();
|
||||
}
|
||||
};
|
||||
jsons.sort(comparator);
|
||||
jsonsTmp.sort(comparator);
|
||||
|
||||
|
||||
for (int i = 0; i < jsons.size(); i++) {
|
||||
assertEquals(jsons.get(i), jsonsTmp.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,6 @@
|
|||
|
||||
package org.apache.dubbo.metrics.filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
|
|
@ -31,13 +25,25 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
|
|||
import org.apache.dubbo.metrics.model.MetricsKey;
|
||||
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
|
||||
import org.apache.dubbo.metrics.model.sample.MetricSample;
|
||||
import org.apache.dubbo.rpc.*;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_PARAMETER_DESC;
|
||||
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.apache.dubbo.metrics.prometheus;
|
||||
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.MetricsConfig;
|
||||
import org.apache.dubbo.config.nested.PrometheusConfig;
|
||||
|
|
|
|||
|
|
@ -18,11 +18,9 @@
|
|||
package org.apache.dubbo.qos.command;
|
||||
|
||||
import org.apache.dubbo.qos.command.exception.NoSuchCommandException;
|
||||
import org.apache.dubbo.qos.command.exception.PermissionDenyException;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
import org.apache.dubbo.qos.permission.PermissionLevel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ import org.apache.dubbo.config.context.ConfigManager;
|
|||
import org.apache.dubbo.metadata.report.MetadataReport;
|
||||
import org.apache.dubbo.metadata.report.MetadataReportInstance;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
|
|||
|
|
@ -110,9 +110,9 @@ public interface Constants {
|
|||
|
||||
int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);
|
||||
|
||||
String EVENT_LOOP_BOSS_POOL_NAME = "NettyServerBoss";
|
||||
String EVENT_LOOP_BOSS_POOL_NAME = "NettyServerBoss";
|
||||
|
||||
String EVENT_LOOP_WORKER_POOL_NAME = "NettyServerWorker";
|
||||
String EVENT_LOOP_WORKER_POOL_NAME = "NettyServerWorker";
|
||||
|
||||
String NETTY_EPOLL_ENABLE_KEY = "netty.epoll.enable";
|
||||
|
||||
|
|
@ -148,4 +148,14 @@ public interface Constants {
|
|||
String CONNECTIONS_KEY = "connections";
|
||||
|
||||
int DEFAULT_BACKLOG = 1024;
|
||||
|
||||
String CONNECTION = "Connection";
|
||||
|
||||
String KEEP_ALIVE = "keep-alive";
|
||||
|
||||
String KEEP_ALIVE_HEADER = "Keep-Alive";
|
||||
|
||||
String OK_HTTP = "ok-http";
|
||||
String URL_CONNECTION = "url-connection";
|
||||
String APACHE_HTTP_CLIENT = "apache-http-client";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,5 +59,23 @@
|
|||
<version>4.5.14</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http;
|
||||
|
||||
|
||||
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
|
||||
|
||||
public abstract class BaseRestClient<CLIENT> implements RestClient {
|
||||
|
||||
protected CLIENT client;
|
||||
|
||||
protected HttpClientConfig clientConfig;
|
||||
|
||||
public BaseRestClient(HttpClientConfig clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
client = createHttpClient(clientConfig);
|
||||
}
|
||||
|
||||
protected abstract CLIENT createHttpClient(HttpClientConfig clientConfig);
|
||||
|
||||
|
||||
public HttpClientConfig getClientConfig() {
|
||||
return clientConfig;
|
||||
}
|
||||
|
||||
public CLIENT getClient() {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http;
|
||||
|
||||
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class RequestTemplate implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final String CONTENT_ENCODING = "Content-Encoding";
|
||||
private static final String CONTENT_LENGTH = "Content-Length";
|
||||
public static final String ENCODING_GZIP = "gzip";
|
||||
public static final String ENCODING_DEFLATE = "deflate";
|
||||
private static final List<String> EMPTY_ARRAYLIST = new ArrayList<>();
|
||||
|
||||
private final Map<String, Collection<String>> queries = new LinkedHashMap<String, Collection<String>>();
|
||||
private final Map<String, Collection<String>> headers = new LinkedHashMap<String, Collection<String>>();
|
||||
private String httpMethod;
|
||||
private String path;
|
||||
private String address;
|
||||
private Object body;
|
||||
private byte[] byteBody = new byte[0];
|
||||
private String protocol = "http://";
|
||||
private final Invocation invocation;
|
||||
private String contextPath = "";
|
||||
|
||||
|
||||
public RequestTemplate(Invocation invocation, String httpMethod, String address) {
|
||||
this(invocation, httpMethod, address, "");
|
||||
}
|
||||
|
||||
public RequestTemplate(Invocation invocation, String httpMethod, String address, String contextPath) {
|
||||
this.httpMethod = httpMethod;
|
||||
this.address = address;
|
||||
this.invocation = invocation;
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
public String getURL() {
|
||||
StringBuilder stringBuilder = new StringBuilder(getProtocol() + address);
|
||||
|
||||
stringBuilder.append(getUri());
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
StringBuilder stringBuilder = new StringBuilder(getContextPath() + path);
|
||||
return stringBuilder.append(getQueryString()).toString();
|
||||
}
|
||||
|
||||
public String getQueryString() {
|
||||
|
||||
if (queries.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder queryBuilder = new StringBuilder("?");
|
||||
for (String field : queries.keySet()) {
|
||||
|
||||
Collection<String> queryValues = queries.get(field);
|
||||
|
||||
if (queryValues == null || queryValues.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String value : queryValues) {
|
||||
queryBuilder.append('&');
|
||||
queryBuilder.append(field);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queryBuilder.append('=');
|
||||
queryBuilder.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
return queryBuilder.toString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public RequestTemplate path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHttpMethod() {
|
||||
return httpMethod;
|
||||
}
|
||||
|
||||
public RequestTemplate httpMethod(String httpMethod) {
|
||||
this.httpMethod = httpMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] getSerializedBody() {
|
||||
return byteBody;
|
||||
}
|
||||
|
||||
public void serializeBody(byte[] body) {
|
||||
addHeader(CONTENT_LENGTH, body.length); // must header
|
||||
this.byteBody = body;
|
||||
}
|
||||
|
||||
public boolean isBodyEmpty() {
|
||||
return getUnSerializedBody() == null;
|
||||
}
|
||||
|
||||
public RequestTemplate body(Object body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object getUnSerializedBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public Map<String, Collection<String>> getAllHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
public Collection<String> getHeaders(String name) {
|
||||
return headers.get(name);
|
||||
}
|
||||
|
||||
public String getHeader(String name) {
|
||||
if (headers.containsKey(name)) {
|
||||
|
||||
Collection<String> headers = getHeaders(name);
|
||||
|
||||
if (headers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String[] strings = headers.toArray(new String[0]);
|
||||
return strings[0];
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<String> getEncodingValues() {
|
||||
if (headers.containsKey(CONTENT_ENCODING)) {
|
||||
return headers.get(CONTENT_ENCODING);
|
||||
}
|
||||
return EMPTY_ARRAYLIST;
|
||||
}
|
||||
|
||||
public boolean isGzipEncodedRequest() {
|
||||
return getEncodingValues().contains(ENCODING_GZIP);
|
||||
}
|
||||
|
||||
public boolean isDeflateEncodedRequest() {
|
||||
return getEncodingValues().contains(ENCODING_DEFLATE);
|
||||
}
|
||||
|
||||
public void addHeader(String key, String value) {
|
||||
addValueByKey(key, value, this.headers);
|
||||
}
|
||||
|
||||
public void addHeader(String key, Object value) {
|
||||
addValueByKey(key, String.valueOf(value), this.headers);
|
||||
}
|
||||
|
||||
public void addKeepAliveHeader(int time) {
|
||||
addHeader(Constants.KEEP_ALIVE_HEADER, time);
|
||||
addHeader(Constants.CONNECTION, Constants.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
public void addHeaders(String key, Collection<String> values) {
|
||||
Collection<String> header = getHeaders(key);
|
||||
|
||||
if (header == null) {
|
||||
header = new HashSet<>();
|
||||
this.headers.put(key, header);
|
||||
}
|
||||
header.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
public void addParam(String key, String value) {
|
||||
addValueByKey(key, value, this.queries);
|
||||
}
|
||||
|
||||
public void addParam(String key, Object value) {
|
||||
addParam(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public Map<String, Collection<String>> getQueries() {
|
||||
return queries;
|
||||
}
|
||||
|
||||
public Collection<String> getParam(String key) {
|
||||
return getQueries().get(key);
|
||||
}
|
||||
|
||||
public void addParams(String key, Collection<String> values) {
|
||||
Collection<String> params = getParam(key);
|
||||
|
||||
if (params == null) {
|
||||
params = new HashSet<>();
|
||||
this.headers.put(key, params);
|
||||
}
|
||||
params.addAll(values);
|
||||
}
|
||||
|
||||
|
||||
public void addValueByKey(String key, String value, Map<String, Collection<String>> maps) {
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<String> values = null;
|
||||
if (!maps.containsKey(key)) {
|
||||
values = new HashSet<>();
|
||||
maps.put(key, values);
|
||||
}
|
||||
values = maps.get(key);
|
||||
|
||||
|
||||
values.add(value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Integer getContentLength() {
|
||||
|
||||
if (!getAllHeaders().containsKey(CONTENT_LENGTH)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<String> strings = (HashSet<String>) getAllHeaders().get(CONTENT_LENGTH);
|
||||
|
||||
return Integer.parseInt(new ArrayList<>(strings).get(0));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
addHeader("Host", address);// must header
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
|
||||
public Invocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
if (contextPath == null || contextPath.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (contextPath.startsWith("/")) {
|
||||
return contextPath;
|
||||
} else {
|
||||
return "/" + contextPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.dubbo.remoting.http;
|
||||
|
||||
import org.apache.dubbo.remoting.RemotingException;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
public interface RestClient {
|
||||
/**
|
||||
* send message.
|
||||
*
|
||||
* @param message
|
||||
* @throws RemotingException
|
||||
*/
|
||||
CompletableFuture<RestResult> send(RequestTemplate message);
|
||||
|
||||
/**
|
||||
* close the channel.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Graceful close the channel.
|
||||
*/
|
||||
void close(int timeout);
|
||||
|
||||
/**
|
||||
* is closed.
|
||||
*
|
||||
* @return closed
|
||||
*/
|
||||
boolean isClosed();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface RestResult {
|
||||
String getContentType();
|
||||
|
||||
byte[] getBody() throws IOException;
|
||||
|
||||
Map<String, List<String>> headers();
|
||||
|
||||
byte[] getErrorResponse() throws IOException;
|
||||
|
||||
int getResponseCode() throws IOException;
|
||||
|
||||
String getMessage() throws IOException;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.config;
|
||||
|
||||
public class HttpClientConfig {
|
||||
private int readTimeout = 6 * 1000;
|
||||
private int writeTimeout = 6 * 1000;
|
||||
private int connectTimeout = 6 * 1000;
|
||||
private int chunkLength = 8196;
|
||||
|
||||
private int HTTP_CLIENT_CONNECTION_MANAGER_MAX_PER_ROUTE = 20;
|
||||
private int HTTP_CLIENT_CONNECTION_MANAGER_MAX_TOTAL = 20;
|
||||
private int HTTPCLIENT_KEEP_ALIVE_DURATION = 30 * 1000;
|
||||
private int HTTP_CLIENT_CONNECTION_MANAGER_CLOSE_WAIT_TIME_MS = 1000;
|
||||
private int HTTP_CLIENT_CONNECTION_MANAGER_CLOSE_IDLE_TIME_S = 30;
|
||||
|
||||
|
||||
public HttpClientConfig() {
|
||||
}
|
||||
|
||||
public int getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public void setReadTimeout(int readTimeout) {
|
||||
this.readTimeout = readTimeout;
|
||||
}
|
||||
|
||||
public int getWriteTimeout() {
|
||||
return writeTimeout;
|
||||
}
|
||||
|
||||
public void setWriteTimeout(int writeTimeout) {
|
||||
this.writeTimeout = writeTimeout;
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public int getChunkLength() {
|
||||
return chunkLength;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* 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.dubbo.remoting.http.factory;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
/**
|
||||
* AbstractHttpClientFactory
|
||||
*/
|
||||
public abstract class AbstractHttpClientFactory implements RestClientFactory {
|
||||
|
||||
protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
|
||||
|
||||
|
||||
// TODO load config
|
||||
protected HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||
|
||||
//////////////////////////////////////// implements start ///////////////////////////////////////////////
|
||||
@Override
|
||||
public RestClient createRestClient(URL url) throws RpcException {
|
||||
|
||||
beforeCreated(url);
|
||||
|
||||
// create a raw client
|
||||
RestClient restClient = doCreateRestClient(url);
|
||||
|
||||
// postprocessor
|
||||
afterCreated(restClient);
|
||||
|
||||
return restClient;
|
||||
}
|
||||
|
||||
//////////////////////////////////////// implements end ///////////////////////////////////////////////
|
||||
|
||||
|
||||
//////////////////////////////////////// inner methods ///////////////////////////////////////////////
|
||||
|
||||
protected void beforeCreated(URL url) {
|
||||
}
|
||||
|
||||
protected abstract RestClient doCreateRestClient(URL url) throws RpcException;
|
||||
|
||||
protected void afterCreated(RestClient client) {
|
||||
}
|
||||
|
||||
//////////////////////////////////////// inner methods ///////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.factory;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Adaptive;
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
/**
|
||||
* RestClientFactory. (API/SPI, Singleton, ThreadSafe)
|
||||
*/
|
||||
@SPI(value = Constants.OK_HTTP, scope = ExtensionScope.FRAMEWORK)
|
||||
public interface RestClientFactory {
|
||||
|
||||
|
||||
@Adaptive({Constants.CLIENT_KEY})
|
||||
RestClient createRestClient(URL url) throws RpcException;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.factory.impl;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.factory.AbstractHttpClientFactory;
|
||||
import org.apache.dubbo.remoting.http.restclient.HttpClientRestClient;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
@Activate(Constants.APACHE_HTTP_CLIENT)
|
||||
public class ApacheHttpClientFactory extends AbstractHttpClientFactory {
|
||||
|
||||
|
||||
@Override
|
||||
protected RestClient doCreateRestClient(URL url) throws RpcException {
|
||||
|
||||
|
||||
return new HttpClientRestClient(httpClientConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.factory.impl;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.factory.AbstractHttpClientFactory;
|
||||
import org.apache.dubbo.remoting.http.restclient.OKHttpRestClient;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
@Activate(Constants.OK_HTTP)
|
||||
public class OkHttpClientFactory extends AbstractHttpClientFactory {
|
||||
|
||||
|
||||
@Override
|
||||
protected RestClient doCreateRestClient(URL url) throws RpcException {
|
||||
|
||||
return new OKHttpRestClient(httpClientConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.factory.impl;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.remoting.Constants;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.factory.AbstractHttpClientFactory;
|
||||
import org.apache.dubbo.remoting.http.restclient.URLConnectionRestClient;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
|
||||
@Activate(Constants.URL_CONNECTION)
|
||||
public class URLConnectionClientFactory extends AbstractHttpClientFactory {
|
||||
|
||||
|
||||
@Override
|
||||
protected RestClient doCreateRestClient(URL url) throws RpcException {
|
||||
|
||||
return new URLConnectionRestClient(httpClientConfig);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.restclient;
|
||||
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.RestResult;
|
||||
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class HttpClientRestClient implements RestClient {
|
||||
private final CloseableHttpClient closeableHttpClient;
|
||||
private final HttpClientConfig httpClientConfig;
|
||||
|
||||
public HttpClientRestClient(HttpClientConfig clientConfig) {
|
||||
closeableHttpClient = createHttpClient();
|
||||
httpClientConfig = clientConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RestResult> send(RequestTemplate requestTemplate) {
|
||||
|
||||
HttpRequestBase httpRequest = null;
|
||||
String httpMethod = requestTemplate.getHttpMethod();
|
||||
|
||||
if ("GET".equals(httpMethod)) {
|
||||
httpRequest = new HttpGet(requestTemplate.getURL());
|
||||
} else if ("POST".equals(httpMethod)) {
|
||||
HttpPost httpPost = new HttpPost(requestTemplate.getURL());
|
||||
httpPost.setEntity(new ByteArrayEntity(requestTemplate.getSerializedBody()));
|
||||
httpRequest = httpPost;
|
||||
}
|
||||
|
||||
Map<String, Collection<String>> allHeaders = requestTemplate.getAllHeaders();
|
||||
|
||||
allHeaders.remove("Content-Length");
|
||||
// header
|
||||
for (String headerName : allHeaders.keySet()) {
|
||||
Collection<String> headerValues = allHeaders.get(headerName);
|
||||
|
||||
for (String headerValue : headerValues) {
|
||||
httpRequest.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
httpRequest.setConfig(getRequestConfig(httpClientConfig));
|
||||
|
||||
CompletableFuture<RestResult> future = new CompletableFuture<>();
|
||||
try {
|
||||
CloseableHttpResponse response = closeableHttpClient.execute(httpRequest);
|
||||
future.complete(new RestResult() {
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return response.getFirstHeader("Content-Type").getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws IOException {
|
||||
return IOUtils.toByteArray(response.getEntity().getContent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> headers() {
|
||||
return Arrays.stream(response.getAllHeaders()).collect(Collectors.toMap(Header::getName, h -> Collections.singletonList(h.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getErrorResponse() throws IOException {
|
||||
return getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() {
|
||||
return response.getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() throws IOException {
|
||||
return response.getStatusLine().getReasonPhrase();
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
private RequestConfig getRequestConfig(HttpClientConfig clientConfig) {
|
||||
|
||||
// TODO config
|
||||
return RequestConfig.custom().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
closeableHttpClient.close();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int timeout) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
// TODO close judge
|
||||
return true;
|
||||
}
|
||||
|
||||
public CloseableHttpClient createHttpClient() {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
|
||||
return HttpClients.custom().setConnectionManager(connectionManager).build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.restclient;
|
||||
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.RestResult;
|
||||
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.internal.http.HttpMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
public class OKHttpRestClient implements RestClient {
|
||||
private final OkHttpClient okHttpClient;
|
||||
private final HttpClientConfig httpClientConfig;
|
||||
|
||||
public OKHttpRestClient(HttpClientConfig clientConfig) {
|
||||
this.okHttpClient = createHttpClient(clientConfig);
|
||||
this.httpClientConfig = clientConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RestResult> send(RequestTemplate requestTemplate) {
|
||||
|
||||
Request.Builder builder = new Request.Builder();
|
||||
// url
|
||||
builder.url(requestTemplate.getURL());
|
||||
|
||||
Map<String, Collection<String>> allHeaders = requestTemplate.getAllHeaders();
|
||||
|
||||
// header
|
||||
for (String headerName : allHeaders.keySet()) {
|
||||
Collection<String> headerValues = allHeaders.get(headerName);
|
||||
|
||||
for (String headerValue : headerValues) {
|
||||
builder.addHeader(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
RequestBody requestBody = null;
|
||||
if (HttpMethod.permitsRequestBody(requestTemplate.getHttpMethod())) {
|
||||
requestBody = RequestBody.create(null, requestTemplate.getSerializedBody());
|
||||
}
|
||||
builder.method(requestTemplate.getHttpMethod(), requestBody);
|
||||
|
||||
CompletableFuture<RestResult> future = new CompletableFuture<>();
|
||||
|
||||
okHttpClient.newCall(builder.build()).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
future.complete(new RestResult() {
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return response.header("Content-Type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws IOException {
|
||||
ResponseBody body = response.body();
|
||||
return body == null ? null : body.bytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> headers() {
|
||||
return response.headers().toMultimap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getErrorResponse() throws IOException {
|
||||
return getBody();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() throws IOException {
|
||||
return response.code();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() throws IOException {
|
||||
return response.message();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
okHttpClient.connectionPool().evictAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int timeout) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return okHttpClient.retryOnConnectionFailure();
|
||||
}
|
||||
|
||||
public OkHttpClient createHttpClient(HttpClientConfig httpClientConfig) {
|
||||
OkHttpClient client = new OkHttpClient.Builder().
|
||||
readTimeout(httpClientConfig.getReadTimeout(), TimeUnit.SECONDS).
|
||||
writeTimeout(httpClientConfig.getWriteTimeout(), TimeUnit.SECONDS).
|
||||
connectTimeout(httpClientConfig.getConnectTimeout(), TimeUnit.SECONDS).
|
||||
build();
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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.dubbo.remoting.http.restclient;
|
||||
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.RestResult;
|
||||
import org.apache.dubbo.remoting.http.config.HttpClientConfig;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
|
||||
public class URLConnectionRestClient implements RestClient {
|
||||
private final HttpClientConfig clientConfig;
|
||||
|
||||
public URLConnectionRestClient(HttpClientConfig clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<RestResult> send(RequestTemplate requestTemplate) {
|
||||
|
||||
CompletableFuture<RestResult> future = new CompletableFuture<>();
|
||||
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(requestTemplate.getURL()).openConnection();
|
||||
connection.setConnectTimeout(clientConfig.getConnectTimeout());
|
||||
connection.setReadTimeout(clientConfig.getReadTimeout());
|
||||
connection.setAllowUserInteraction(false);
|
||||
connection.setInstanceFollowRedirects(true);
|
||||
connection.setRequestMethod(requestTemplate.getHttpMethod());
|
||||
|
||||
// writeHeaders
|
||||
|
||||
for (String field : requestTemplate.getAllHeaders().keySet()) {
|
||||
for (String value : requestTemplate.getHeaders(field)) {
|
||||
connection.addRequestProperty(field, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// writeBody
|
||||
|
||||
boolean gzipEncodedRequest = requestTemplate.isGzipEncodedRequest();
|
||||
boolean deflateEncodedRequest = requestTemplate.isDeflateEncodedRequest();
|
||||
if (requestTemplate.isBodyEmpty()) {
|
||||
future.complete(new RestResult() {
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return connection.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws IOException {
|
||||
return IOUtils.toByteArray(connection.getInputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> headers() {
|
||||
return connection.getHeaderFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getErrorResponse() throws IOException {
|
||||
return IOUtils.toByteArray(connection.getErrorStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() throws IOException {
|
||||
return connection.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() throws IOException {
|
||||
return connection.getResponseMessage();
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
Integer contentLength = requestTemplate.getContentLength();
|
||||
|
||||
if (contentLength != null) {
|
||||
connection.setFixedLengthStreamingMode(contentLength);
|
||||
} else {
|
||||
connection.setChunkedStreamingMode(clientConfig.getChunkLength());
|
||||
}
|
||||
connection.setDoOutput(true);
|
||||
|
||||
OutputStream out = connection.getOutputStream();
|
||||
if (gzipEncodedRequest) {
|
||||
out = new GZIPOutputStream(out);
|
||||
} else if (deflateEncodedRequest) {
|
||||
out = new DeflaterOutputStream(out);
|
||||
}
|
||||
try {
|
||||
out.write(requestTemplate.getSerializedBody());
|
||||
} finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException suppressed) {
|
||||
}
|
||||
}
|
||||
|
||||
future.complete(new RestResult() {
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return connection.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBody() throws IOException {
|
||||
return IOUtils.toByteArray(connection.getInputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> headers() {
|
||||
return connection.getHeaderFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getErrorResponse() throws IOException {
|
||||
return IOUtils.toByteArray(connection.getErrorStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResponseCode() throws IOException {
|
||||
return connection.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() throws IOException {
|
||||
return connection.getResponseMessage();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int timeout) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ok-http=org.apache.dubbo.remoting.http.factory.impl.OkHttpClientFactory
|
||||
url-connection=org.apache.dubbo.remoting.http.factory.impl.URLConnectionClientFactory
|
||||
apache-http-client=org.apache.dubbo.remoting.http.factory.impl.ApacheHttpClientFactory
|
||||
|
||||
|
|
@ -29,7 +29,6 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
|
|
|||
|
|
@ -45,19 +45,14 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
/**
|
||||
* AbstractProxyProtocol
|
||||
*/
|
||||
public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
||||
|
||||
private final List<Class<?>> rpcExceptions = new CopyOnWriteArrayList<Class<?>>();
|
||||
protected final List<Class<?>> rpcExceptions = new CopyOnWriteArrayList<Class<?>>();
|
||||
|
||||
protected ProxyFactory proxyFactory;
|
||||
|
||||
|
|
@ -139,48 +134,6 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
return exporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> Invoker<T> protocolBindingRefer(final Class<T> type, final URL url) throws RpcException {
|
||||
final Invoker<T> target = proxyFactory.getInvoker(doRefer(type, url), type, url);
|
||||
Invoker<T> invoker = new AbstractInvoker<T>(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) {
|
||||
try {
|
||||
invocation.setAttachment(PATH_KEY, getUrl().getPath());
|
||||
invocation.setAttachment(VERSION_KEY, version);
|
||||
Result result = target.invoke(invocation);
|
||||
// FIXME result is an AsyncRpcResult instance.
|
||||
Throwable e = result.getException();
|
||||
if (e != null) {
|
||||
for (Class<?> rpcException : rpcExceptions) {
|
||||
if (rpcException.isAssignableFrom(e.getClass())) {
|
||||
throw getRpcException(type, url, invocation, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (RpcException e) {
|
||||
if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
|
||||
e.setCode(getErrorCode(e.getCause()));
|
||||
}
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
throw getRpcException(type, url, invocation, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
target.destroy();
|
||||
invokers.remove(this);
|
||||
AbstractProxyProtocol.this.destroyInternal(url);
|
||||
}
|
||||
};
|
||||
invokers.add(invoker);
|
||||
return invoker;
|
||||
}
|
||||
|
||||
// used to destroy unused clients and other resource
|
||||
protected void destroyInternal(URL url) {
|
||||
// subclass override
|
||||
|
|
@ -207,8 +160,6 @@ public abstract class AbstractProxyProtocol extends AbstractProtocol {
|
|||
|
||||
protected abstract <T> Runnable doExport(T impl, Class<T> type, URL url) throws RpcException;
|
||||
|
||||
protected abstract <T> T doRefer(Class<T> type, URL url) throws RpcException;
|
||||
|
||||
protected class ProxyProtocolServer implements ProtocolServer {
|
||||
|
||||
private RemotingServer server;
|
||||
|
|
|
|||
|
|
@ -18,11 +18,9 @@ package org.apache.dubbo.rpc;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import org.apache.dubbo.common.url.component.URLParam;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<parent>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-rpc</artifactId>
|
||||
<version>${revision}</version>
|
||||
|
|
@ -112,10 +112,48 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metadata-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-http</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Web MVC -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -16,16 +16,16 @@
|
|||
*/
|
||||
package org.apache.dubbo.rpc.protocol.rest;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
|
||||
import io.netty.channel.ChannelOption;
|
||||
import org.jboss.resteasy.plugins.server.netty.NettyJaxrsServer;
|
||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_THREADS;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
|
||||
|
|
|
|||
|
|
@ -19,32 +19,31 @@ package org.apache.dubbo.rpc.protocol.rest;
|
|||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.reference.ReferenceCountedResource;
|
||||
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_CLIENT;
|
||||
|
||||
public class ReferenceCountedClient extends ReferenceCountedResource {
|
||||
public class ReferenceCountedClient<T extends RestClient> extends ReferenceCountedResource {
|
||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ReferenceCountedClient.class);
|
||||
|
||||
private final ResteasyClient resteasyClient;
|
||||
private T client;
|
||||
|
||||
public ReferenceCountedClient(ResteasyClient resteasyClient) {
|
||||
this.resteasyClient = resteasyClient;
|
||||
public ReferenceCountedClient(T client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public ResteasyClient getClient() {
|
||||
return resteasyClient;
|
||||
public T getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public boolean isDestroyed() {
|
||||
return resteasyClient.isClosed();
|
||||
return client.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroy() {
|
||||
try {
|
||||
resteasyClient.close();
|
||||
client.close();
|
||||
} catch (Exception e) {
|
||||
logger.error(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", "Close resteasy client error", e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,72 +19,73 @@ package org.apache.dubbo.rpc.protocol.rest;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.remoting.http.HttpBinder;
|
||||
import org.apache.dubbo.metadata.ParameterTypesComparator;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.media.MediaType;
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.remoting.http.RestClient;
|
||||
import org.apache.dubbo.remoting.http.RestResult;
|
||||
import org.apache.dubbo.remoting.http.factory.RestClientFactory;
|
||||
import org.apache.dubbo.remoting.http.servlet.BootstrapListener;
|
||||
import org.apache.dubbo.remoting.http.servlet.ServletManager;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.AsyncRpcResult;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.ProtocolServer;
|
||||
import org.apache.dubbo.rpc.Result;
|
||||
import org.apache.dubbo.rpc.RpcException;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.AbstractInvoker;
|
||||
import org.apache.dubbo.rpc.protocol.AbstractProxyProtocol;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionConfig;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionCreateContext;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionPreBuildIntercept;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.metadata.MetadataResolver;
|
||||
import org.apache.dubbo.rpc.protocol.rest.exception.HttpClientException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.exception.RemoteServerInternalException;
|
||||
import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodecManager;
|
||||
import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
|
||||
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HeaderElementIterator;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.config.SocketConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeaderElementIterator;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
|
||||
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
||||
import org.jboss.resteasy.util.GetRestful;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_CLIENT;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_SERVER;
|
||||
import static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.CONNECT_TIMEOUT_KEY;
|
||||
import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT;
|
||||
import static org.apache.dubbo.remoting.Constants.SERVER_KEY;
|
||||
import static org.apache.dubbo.rpc.protocol.rest.Constants.EXTENSION_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
|
||||
|
||||
public class RestProtocol extends AbstractProxyProtocol {
|
||||
|
||||
private static final int DEFAULT_PORT = 80;
|
||||
private static final String DEFAULT_SERVER = "jetty";
|
||||
|
||||
private static final int HTTPCLIENTCONNECTIONMANAGER_MAXPERROUTE = 20;
|
||||
private static final int HTTPCLIENTCONNECTIONMANAGER_MAXTOTAL = 20;
|
||||
private static final int HTTPCLIENT_KEEPALIVEDURATION = 30 * 1000;
|
||||
private static final int HTTPCLIENTCONNECTIONMANAGER_CLOSEWAITTIME_MS = 1000;
|
||||
private static final int HTTPCLIENTCONNECTIONMANAGER_CLOSEIDLETIME_S = 30;
|
||||
private static final String DEFAULT_CLIENT = org.apache.dubbo.remoting.Constants.OK_HTTP;
|
||||
|
||||
private final RestServerFactory serverFactory = new RestServerFactory();
|
||||
|
||||
private final ConcurrentMap<String, ReferenceCountedClient> clients = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, ReferenceCountedClient<? extends RestClient>> clients = new ConcurrentHashMap<>();
|
||||
|
||||
private volatile ConnectionMonitor connectionMonitor;
|
||||
private final RestClientFactory clientFactory;
|
||||
|
||||
public RestProtocol() {
|
||||
private final Set<HttpConnectionPreBuildIntercept> httpConnectionPreBuildIntercepts;
|
||||
|
||||
public RestProtocol(FrameworkModel frameworkModel) {
|
||||
super(WebApplicationException.class, ProcessingException.class);
|
||||
this.clientFactory = frameworkModel.getExtensionLoader(RestClientFactory.class).getAdaptiveExtension();
|
||||
this.httpConnectionPreBuildIntercepts = frameworkModel.getExtensionLoader(HttpConnectionPreBuildIntercept.class).getSupportedExtensionInstances();
|
||||
}
|
||||
|
||||
public void setHttpBinder(HttpBinder httpBinder) {
|
||||
serverFactory.setHttpBinder(httpBinder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultPort() {
|
||||
|
|
@ -135,79 +136,100 @@ public class RestProtocol extends AbstractProxyProtocol {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException {
|
||||
ReferenceCountedClient referenceCountedClient = ConcurrentHashMapUtils.computeIfAbsent(clients, url.getAddress(), _key -> {
|
||||
// TODO more configs to add
|
||||
return createReferenceCountedClient(url);
|
||||
});
|
||||
protected <T> Invoker<T> protocolBindingRefer(final Class<T> type, final URL url) throws RpcException {
|
||||
|
||||
if (referenceCountedClient.isDestroyed()) {
|
||||
referenceCountedClient = createReferenceCountedClient(url);
|
||||
clients.put(url.getAddress(), referenceCountedClient);
|
||||
}
|
||||
referenceCountedClient.retain();
|
||||
ReferenceCountedClient<? extends RestClient> refClient =
|
||||
clients.computeIfAbsent(url.getAddress(), key -> createReferenceCountedClient(url));
|
||||
|
||||
ResteasyClient resteasyClient = referenceCountedClient.getClient();
|
||||
for (String clazz : COMMA_SPLIT_PATTERN.split(url.getParameter(EXTENSION_KEY, ""))) {
|
||||
if (!StringUtils.isEmpty(clazz)) {
|
||||
refClient.retain();
|
||||
|
||||
// resolve metadata
|
||||
Map<String, Map<ParameterTypesComparator, RestMethodMetadata>> metadataMap = MetadataResolver.resolveConsumerServiceMetadata(type, url);
|
||||
|
||||
Invoker<T> invoker = new AbstractInvoker<T>(type, url, new String[]{INTERFACE_KEY, GROUP_KEY, TOKEN_KEY}) {
|
||||
@Override
|
||||
protected Result doInvoke(Invocation invocation) {
|
||||
try {
|
||||
resteasyClient.register(Thread.currentThread().getContextClassLoader().loadClass(clazz.trim()));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RpcException("Error loading JAX-RS extension class: " + clazz.trim(), e);
|
||||
RestMethodMetadata restMethodMetadata = metadataMap.get(invocation.getMethodName()).get(ParameterTypesComparator.getInstance(invocation.getParameterTypes()));
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate(invocation, restMethodMetadata.getRequest().getMethod(), url.getAddress(), getContextPath(url));
|
||||
|
||||
HttpConnectionCreateContext httpConnectionCreateContext = new HttpConnectionCreateContext();
|
||||
// TODO dynamic load config
|
||||
httpConnectionCreateContext.setConnectionConfig(new HttpConnectionConfig());
|
||||
httpConnectionCreateContext.setRequestTemplate(requestTemplate);
|
||||
httpConnectionCreateContext.setRestMethodMetadata(restMethodMetadata);
|
||||
httpConnectionCreateContext.setInvocation(invocation);
|
||||
httpConnectionCreateContext.setUrl(url);
|
||||
|
||||
for (HttpConnectionPreBuildIntercept intercept : httpConnectionPreBuildIntercepts) {
|
||||
intercept.intercept(httpConnectionCreateContext);
|
||||
}
|
||||
|
||||
CompletableFuture<RestResult> future = refClient.getClient().send(requestTemplate);
|
||||
CompletableFuture<AppResponse> responseFuture = new CompletableFuture<>();
|
||||
AsyncRpcResult asyncRpcResult = new AsyncRpcResult(responseFuture, invocation);
|
||||
future.whenComplete((r, t) -> {
|
||||
if (t != null) {
|
||||
responseFuture.completeExceptionally(t);
|
||||
} else {
|
||||
AppResponse appResponse = new AppResponse();
|
||||
try {
|
||||
int responseCode = r.getResponseCode();
|
||||
MediaType mediaType = MediaType.TEXT_PLAIN;
|
||||
|
||||
if (400 < responseCode && responseCode < 500) {
|
||||
throw new HttpClientException(r.getMessage());
|
||||
} else if (responseCode >= 500) {
|
||||
throw new RemoteServerInternalException(r.getMessage());
|
||||
} else if (responseCode < 400) {
|
||||
mediaType = MediaTypeUtil.convertMediaType(r.getContentType());
|
||||
}
|
||||
|
||||
|
||||
Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(),
|
||||
restMethodMetadata.getReflectMethod().getReturnType(), mediaType);
|
||||
appResponse.setValue(value);
|
||||
Map<String, String> headers = r.headers()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
appResponse.setAttachments(headers);
|
||||
responseFuture.complete(appResponse);
|
||||
} catch (Exception e) {
|
||||
responseFuture.completeExceptionally(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
return asyncRpcResult;
|
||||
} catch (RpcException e) {
|
||||
if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
|
||||
e.setCode(getErrorCode(e.getCause()));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO protocol
|
||||
ResteasyWebTarget target = resteasyClient.target("http://" + url.getAddress() + "/" + getContextPath(url));
|
||||
return target.proxy(serviceType);
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
invokers.remove(this);
|
||||
destroyInternal(url);
|
||||
}
|
||||
};
|
||||
invokers.add(invoker);
|
||||
return invoker;
|
||||
}
|
||||
|
||||
private ReferenceCountedClient createReferenceCountedClient(URL url) {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
|
||||
// 20 is the default maxTotal of current PoolingClientConnectionManager
|
||||
connectionManager.setMaxTotal(url.getParameter(CONNECTIONS_KEY, HTTPCLIENTCONNECTIONMANAGER_MAXTOTAL));
|
||||
connectionManager.setDefaultMaxPerRoute(url.getParameter(CONNECTIONS_KEY, HTTPCLIENTCONNECTIONMANAGER_MAXPERROUTE));
|
||||
if (connectionMonitor == null) {
|
||||
connectionMonitor = new ConnectionMonitor();
|
||||
connectionMonitor.start();
|
||||
}
|
||||
connectionMonitor.addConnectionManager(url.getAddress(), connectionManager);
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(url.getParameter(CONNECT_TIMEOUT_KEY, DEFAULT_CONNECT_TIMEOUT))
|
||||
.setSocketTimeout(url.getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT))
|
||||
.build();
|
||||
private ReferenceCountedClient<? extends RestClient> createReferenceCountedClient(URL url) throws RpcException {
|
||||
|
||||
SocketConfig socketConfig = SocketConfig.custom()
|
||||
.setSoKeepAlive(true)
|
||||
.setTcpNoDelay(true)
|
||||
.build();
|
||||
// url -> RestClient
|
||||
RestClient restClient = clientFactory.createRestClient(url);
|
||||
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create()
|
||||
.setConnectionManager(connectionManager)
|
||||
.setKeepAliveStrategy((response, context) -> {
|
||||
HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
|
||||
while (it.hasNext()) {
|
||||
HeaderElement he = it.nextElement();
|
||||
String param = he.getName();
|
||||
String value = he.getValue();
|
||||
if (value != null && param.equalsIgnoreCase(TIMEOUT_KEY)) {
|
||||
return Long.parseLong(value) * 1000;
|
||||
}
|
||||
}
|
||||
return HTTPCLIENT_KEEPALIVEDURATION;
|
||||
})
|
||||
.setDefaultRequestConfig(requestConfig)
|
||||
.setDefaultSocketConfig(socketConfig)
|
||||
.build();
|
||||
|
||||
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient/*, localContext*/);
|
||||
|
||||
ResteasyClient resteasyClient = new ResteasyClientBuilder().httpEngine(engine).build();
|
||||
resteasyClient.register(RpcContextFilter.class);
|
||||
return new ReferenceCountedClient(resteasyClient);
|
||||
return new ReferenceCountedClient<>(restClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -223,10 +245,6 @@ public class RestProtocol extends AbstractProxyProtocol {
|
|||
}
|
||||
super.destroy();
|
||||
|
||||
if (connectionMonitor != null) {
|
||||
connectionMonitor.shutdown();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, ProtocolServer> entry : serverMap.entrySet()) {
|
||||
try {
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
|
@ -281,55 +299,9 @@ public class RestProtocol extends AbstractProxyProtocol {
|
|||
ReferenceCountedClient referenceCountedClient = clients.get(url.getAddress());
|
||||
if (referenceCountedClient != null && referenceCountedClient.release()) {
|
||||
clients.remove(url.getAddress());
|
||||
connectionMonitor.destroyManager(url);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", "Failed to close unused resources in rest protocol. interfaceName [" + url.getServiceInterface() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected class ConnectionMonitor extends Thread {
|
||||
private volatile boolean shutdown;
|
||||
/**
|
||||
* The lifecycle of {@code PoolingHttpClientConnectionManager} instance is bond with ReferenceCountedClient
|
||||
*/
|
||||
private final Map<String, PoolingHttpClientConnectionManager> connectionManagers = new ConcurrentHashMap<>();
|
||||
|
||||
public void addConnectionManager(String address, PoolingHttpClientConnectionManager connectionManager) {
|
||||
connectionManagers.putIfAbsent(address, connectionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!shutdown) {
|
||||
synchronized (this) {
|
||||
wait(HTTPCLIENTCONNECTIONMANAGER_CLOSEWAITTIME_MS);
|
||||
for (PoolingHttpClientConnectionManager connectionManager : connectionManagers.values()) {
|
||||
connectionManager.closeExpiredConnections();
|
||||
connectionManager.closeIdleConnections(HTTPCLIENTCONNECTIONMANAGER_CLOSEIDLETIME_S, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
shutdown = true;
|
||||
connectionManagers.clear();
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
// destroy the connection manager of a specific address when ReferenceCountedClient is destroyed.
|
||||
private void destroyManager(URL url) {
|
||||
PoolingHttpClientConnectionManager connectionManager = connectionManagers.remove(url.getAddress());
|
||||
if (connectionManager != null) {
|
||||
connectionManager.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,19 +17,15 @@
|
|||
package org.apache.dubbo.rpc.protocol.rest;
|
||||
|
||||
import org.apache.dubbo.remoting.http.HttpBinder;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
||||
/**
|
||||
* Only the server that implements servlet container
|
||||
* could support something like @Context injection of servlet objects.
|
||||
*
|
||||
*/
|
||||
public class RestServerFactory {
|
||||
|
||||
private HttpBinder httpBinder;
|
||||
|
||||
public void setHttpBinder(HttpBinder httpBinder) {
|
||||
this.httpBinder = httpBinder;
|
||||
}
|
||||
private static final HttpBinder httpBinder = FrameworkModel.defaultModel().getAdaptiveExtension(HttpBinder.class);
|
||||
|
||||
public RestProtocolServer createServer(String name) {
|
||||
// TODO move names to Constants
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation;
|
||||
|
||||
|
||||
import org.apache.dubbo.metadata.rest.ArgInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BaseParseContext {
|
||||
|
||||
|
||||
protected List<Object> args;
|
||||
|
||||
protected List<ArgInfo> argInfos;
|
||||
|
||||
|
||||
public List<Object> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(List<Object> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public List<ArgInfo> getArgInfos() {
|
||||
return argInfos;
|
||||
}
|
||||
|
||||
public void setArgInfos(List<ArgInfo> argInfos) {
|
||||
this.argInfos = argInfos;
|
||||
}
|
||||
|
||||
public ArgInfo getArgInfoByIndex(int index) {
|
||||
return getArgInfos().get(index);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation;
|
||||
|
||||
import org.apache.dubbo.metadata.rest.ArgInfo;
|
||||
|
||||
|
||||
public interface ParamParser<T> {
|
||||
void parse(T parseContext, ArgInfo argInfo);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation;
|
||||
|
||||
|
||||
import org.apache.dubbo.metadata.rest.ArgInfo;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.consumer.BaseConsumerParamParser;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.consumer.ConsumerParseContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ParamParserManager {
|
||||
|
||||
|
||||
private static final Set<BaseConsumerParamParser> consumerParamParsers =
|
||||
FrameworkModel.defaultModel().getExtensionLoader(BaseConsumerParamParser.class).getSupportedExtensionInstances();
|
||||
|
||||
/**
|
||||
* provider Design Description:
|
||||
* <p>
|
||||
* Object[] args=new Object[0];
|
||||
* List<Object> argsList=new ArrayList<>;</>
|
||||
* <p>
|
||||
* setValueByIndex(int index,Object value);
|
||||
* <p>
|
||||
* args=toArray(new Object[0]);
|
||||
*/
|
||||
public void consumerParamParse(ConsumerParseContext parseContext) {
|
||||
|
||||
List<Object> args = parseContext.getArgs();
|
||||
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
for (BaseConsumerParamParser paramParser : consumerParamParsers) {
|
||||
ArgInfo argInfoByIndex = parseContext.getArgInfoByIndex(i);
|
||||
|
||||
if (!paramParser.paramTypeMatch(argInfoByIndex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
paramParser.parse(parseContext, argInfoByIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation.consumer;
|
||||
|
||||
|
||||
import org.apache.dubbo.common.serialize.Constants;
|
||||
|
||||
public class HttpConnectionConfig {
|
||||
|
||||
|
||||
private int connectTimeout;
|
||||
private int readTimeout;
|
||||
private int chunkLength = 8196;
|
||||
private byte serialization = Constants.FASTJSON2_SERIALIZATION_ID;
|
||||
private int keepAlive = 60;
|
||||
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public int getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public int getChunkLength() {
|
||||
return chunkLength;
|
||||
}
|
||||
|
||||
public byte getSerialization() {
|
||||
return serialization;
|
||||
}
|
||||
|
||||
public int getKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation.consumer;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.metadata.rest.RestMethodMetadata;
|
||||
import org.apache.dubbo.metadata.rest.ServiceRestMetadata;
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.rpc.Invocation;
|
||||
|
||||
public class HttpConnectionCreateContext {
|
||||
|
||||
private RequestTemplate requestTemplate;
|
||||
private HttpConnectionConfig connectionConfig;
|
||||
private RestMethodMetadata restMethodMetadata;
|
||||
private Invocation invocation;
|
||||
private URL url;
|
||||
|
||||
public HttpConnectionCreateContext() {
|
||||
}
|
||||
|
||||
|
||||
public void setRequestTemplate(RequestTemplate requestTemplate) {
|
||||
this.requestTemplate = requestTemplate;
|
||||
}
|
||||
|
||||
public void setConnectionConfig(HttpConnectionConfig connectionConfig) {
|
||||
this.connectionConfig = connectionConfig;
|
||||
}
|
||||
|
||||
|
||||
public RequestTemplate getRequestTemplate() {
|
||||
return requestTemplate;
|
||||
}
|
||||
|
||||
public HttpConnectionConfig getConnectionConfig() {
|
||||
return connectionConfig;
|
||||
}
|
||||
|
||||
public ServiceRestMetadata getServiceRestMetadata() {
|
||||
return restMethodMetadata.getServiceRestMetadata();
|
||||
}
|
||||
|
||||
public RestMethodMetadata getRestMethodMetadata() {
|
||||
return restMethodMetadata;
|
||||
}
|
||||
|
||||
public void setRestMethodMetadata(RestMethodMetadata restMethodMetadata) {
|
||||
this.restMethodMetadata = restMethodMetadata;
|
||||
}
|
||||
|
||||
public Invocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
|
||||
public void setInvocation(Invocation invocation) {
|
||||
this.invocation = invocation;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation.consumer;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
@SPI(scope = ExtensionScope.FRAMEWORK)
|
||||
public interface HttpConnectionPreBuildIntercept {
|
||||
void intercept(HttpConnectionCreateContext connectionCreateContext);
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.dubbo.rpc.protocol.rest.annotation.consumer.inercept;
|
||||
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.metadata.rest.ServiceRestMetadata;
|
||||
import org.apache.dubbo.remoting.http.RequestTemplate;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionConfig;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionCreateContext;
|
||||
import org.apache.dubbo.rpc.protocol.rest.annotation.consumer.HttpConnectionPreBuildIntercept;
|
||||
import org.apache.dubbo.rpc.protocol.rest.constans.RestConstant;
|
||||
|
||||
@Activate(value = RestConstant.ADD_MUST_ATTTACHMENT,order = 1)
|
||||
public class AddMustAttachmentIntercept implements HttpConnectionPreBuildIntercept {
|
||||
|
||||
@Override
|
||||
public void intercept(HttpConnectionCreateContext connectionCreateContext) {
|
||||
|
||||
RequestTemplate requestTemplate = connectionCreateContext.getRequestTemplate();
|
||||
ServiceRestMetadata serviceRestMetadata = connectionCreateContext.getServiceRestMetadata();
|
||||
HttpConnectionConfig connectionConfig = connectionCreateContext.getConnectionConfig();
|
||||
|
||||
|
||||
requestTemplate.addHeader(RestConstant.GROUP, serviceRestMetadata.getGroup());
|
||||
requestTemplate.addHeader(RestConstant.VERSION, serviceRestMetadata.getVersion());
|
||||
requestTemplate.addHeader(RestConstant.PATH, serviceRestMetadata.getServiceInterface());
|
||||
requestTemplate.addKeepAliveHeader(connectionConfig.getKeepAlive());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue