Explorar el Código

保存熔断规则接口优化

dengsixing hace 3 años
padre
commit
9c8ca49c1c
Se han modificado 100 ficheros con 6146 adiciones y 0 borrados
  1. 53 0
      .circleci/config.yml
  2. 49 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java
  3. 116 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java
  4. 34 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DefaultDubboOriginParser.java
  5. 38 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginParser.java
  6. 80 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/DubboTestUtil.java
  7. 75 0
      sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginRegistryTest.java
  8. 75 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/README.md
  9. 69 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/pom.xml
  10. 76 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientBuilder.java
  11. 59 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfig.java
  12. 26 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/ApacheHttpClientResourceExtractor.java
  13. 29 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/DefaultApacheHttpClientResourceExtractor.java
  14. 33 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallback.java
  15. 38 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/DefaultApacheHttpClientFallback.java
  16. 109 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientTest.java
  17. 30 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/TestApplication.java
  18. 37 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/controller/TestController.java
  19. 42 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfigTest.java
  20. 34 0
      sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallbackTest.java
  21. 1 0
      sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot
  22. 108 0
      sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAdapterGlobalConfig.java
  23. 35 0
      sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DefaultDubboOriginParser.java
  24. 38 0
      sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginParser.java
  25. 76 0
      sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginRegistryTest.java
  26. 83 0
      sentinel-adapter/sentinel-jax-rs-adapter/README.md
  27. 74 0
      sentinel-adapter/sentinel-jax-rs-adapter/pom.xml
  28. 79 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsClientTemplate.java
  29. 88 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsProviderFilter.java
  30. 62 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/config/SentinelJaxRsConfig.java
  31. 39 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/exception/DefaultExceptionMapper.java
  32. 45 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/fallback/DefaultSentinelJaxRsFallback.java
  33. 43 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/fallback/SentinelJaxRsFallback.java
  34. 81 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/future/FutureWrapper.java
  35. 31 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/DefaultRequestOriginParser.java
  36. 33 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/DefaultResourceNameParser.java
  37. 34 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/RequestOriginParser.java
  38. 27 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/ResourceNameParser.java
  39. 413 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/ClientFilterTest.java
  40. 257 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/ProviderFilterTest.java
  41. 30 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/TestApplication.java
  42. 92 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/TestResource.java
  43. 3 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/resources/application-client.yml
  44. 3 0
      sentinel-adapter/sentinel-jax-rs-adapter/src/test/resources/application-provider.yml
  45. 38 0
      sentinel-adapter/sentinel-motan-adapter/pom.xml
  46. 89 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/MotanUtils.java
  47. 74 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/SentinelMotanConsumerFilter.java
  48. 80 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/SentinelMotanProviderFilter.java
  49. 94 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/config/MotanAdapterGlobalConfig.java
  50. 38 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/fallback/DefaultMotanFallback.java
  51. 37 0
      sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/fallback/MotanFallback.java
  52. 2 0
      sentinel-adapter/sentinel-motan-adapter/src/main/resources/META-INF/services/com.weibo.api.motan.filter.Filter
  53. 65 0
      sentinel-adapter/sentinel-okhttp-adapter/README.md
  54. 68 0
      sentinel-adapter/sentinel-okhttp-adapter/pom.xml
  55. 78 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpConfig.java
  56. 67 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpInterceptor.java
  57. 30 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/DefaultOkHttpResourceExtractor.java
  58. 34 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/OkHttpResourceExtractor.java
  59. 34 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/DefaultOkHttpFallback.java
  60. 29 0
      sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/OkHttpFallback.java
  61. 98 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpInterceptorTest.java
  62. 30 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/app/TestApplication.java
  63. 37 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/app/controller/TestController.java
  64. 38 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/config/SentinelOkHttpConfigTest.java
  65. 59 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/OkHttpResourceExtractorTest.java
  66. 34 0
      sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/OkHttpFallbackTest.java
  67. 72 0
      sentinel-adapter/sentinel-quarkus-adapter/README.md
  68. 55 0
      sentinel-adapter/sentinel-quarkus-adapter/pom.xml
  69. 72 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/pom.xml
  70. 46 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/SentinelAnnotationQuarkusAdapterProcessor.java
  71. 84 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/FooService.java
  72. 37 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/FooUtil.java
  73. 195 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/SentinelAnnotationQuarkusAdapterTest.java
  74. 63 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-runtime/pom.xml
  75. 13 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml
  76. 77 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/pom.xml
  77. 37 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/SentinelJaxRsQuarkusAdapterProcessor.java
  78. 242 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/SentinelJaxRsQuarkusAdapterTest.java
  79. 90 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/TestResource.java
  80. 63 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/pom.xml
  81. 14 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml
  82. 2 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers
  83. 60 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-deployment/pom.xml
  84. 73 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/nativeimage/SentinelNativeImageProcessor.java
  85. 75 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/pom.xml
  86. 52 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/nativeimage/SentinelRecorder.java
  87. 13 0
      sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml
  88. 64 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/README.md
  89. 43 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml
  90. 72 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java
  91. 27 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelConstants.java
  92. 84 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java
  93. 93 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java
  94. 61 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java
  95. 37 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java
  96. 39 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java
  97. 50 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java
  98. 3 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter
  99. 108 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java
  100. 0 0
      sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java

+ 53 - 0
.circleci/config.yml

@@ -0,0 +1,53 @@
+version: 2
+jobs:
+  integration-test:
+    docker:
+      - image: circleci/openjdk:8-jdk
+    working_directory: ~/sentinel
+    environment:
+      MAVEN_OPTS: -Xmx3200m
+    steps:
+      - checkout
+      # Run tests
+      - run: mvn integration-test
+
+  document-lint:
+    docker: 
+      # this image is build from Dockerfile 
+      # https://github.com/pouchcontainer/pouchlinter/blob/master/Dockerfile
+      - image: pouchcontainer/pouchlinter:v0.1.2
+    working_directory: ~/sentinel
+    steps:
+      - checkout
+      - run:
+          name: use markdownlint v0.5.0 to lint markdown file (https://github.com/markdownlint/markdownlint)
+          command: |
+            find  ./ -name  "*.md" | grep -v vendor | grep -v commandline |  grep -v .github |  grep -v swagger |  grep -v api |  xargs mdl -r ~MD010,~MD013,~MD024,~MD029,~MD033,~MD036
+#      - run:
+#          name: use markdown-link-check(https://github.com/tcort/markdown-link-check) to check links in markdown files
+#          command: |
+#            set +e
+#            for name in $(find . -name \*.md | grep -v vendor | grep -v CHANGELOG); do
+#              if [ -f $name ]; then
+#                markdown-link-check -q $name;
+#                if [ $? -ne 0 ]; then
+#                  code=1
+#                fi
+#              fi
+#            done
+#            bash -c "exit $code";
+#      - run:
+#          name: use opensource tool client9/misspell to correct commonly misspelled English words
+#          command: |
+#            find  ./* -name  "*"  | grep -v vendor | xargs misspell -error
+#      - run:
+#          name: use ShellCheck (https://github.com/koalaman/shellcheck) to check the validateness of shell scripts in pouch repo
+#          command: |
+#            find ./ -name "*.sh" | grep -v vendor | xargs shellcheck
+
+workflows:
+  version: 2
+  ci:
+    jobs:
+      - integration-test
+      - document-lint

+ 49 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/BaseSentinelDubboFilter.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.dubbo;
+
+
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+/**
+ * Base class of the {@link SentinelDubboProviderFilter} and {@link SentinelDubboConsumerFilter}.
+ *
+ * @author Zechao Zheng
+ */
+public abstract class BaseSentinelDubboFilter implements Filter {
+
+
+    /**
+     * Get method name of dubbo rpc
+     *
+     * @param invoker
+     * @param invocation
+     * @return
+     */
+    abstract String getMethodName(Invoker invoker, Invocation invocation, String prefix);
+
+    /**
+     * Get interface name of dubbo rpc
+     *
+     * @param invoker
+     * @return
+     */
+    abstract String getInterfaceName(Invoker invoker, String prefix);
+
+
+}

+ 116 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/config/DubboAdapterGlobalConfig.java

@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.dubbo.config;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback;
+import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback;
+import com.alibaba.csp.sentinel.adapter.dubbo.origin.DefaultDubboOriginParser;
+import com.alibaba.csp.sentinel.adapter.dubbo.origin.DubboOriginParser;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+/**
+ * <p>
+ * Responsible for dubbo service provider, consumer attribute configuration
+ * </p>
+ *
+ * @author lianglin
+ * @since 1.7.0
+ */
+public final class DubboAdapterGlobalConfig {
+
+    private static final String TRUE_STR = "true";
+
+    public static final String DUBBO_RES_NAME_WITH_PREFIX_KEY = "csp.sentinel.dubbo.resource.use.prefix";
+    public static final String DUBBO_PROVIDER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.provider.prefix";
+    public static final String DUBBO_CONSUMER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.consumer.prefix";
+
+    private static final String DEFAULT_DUBBO_PROVIDER_PREFIX = "dubbo:provider:";
+    private static final String DEFAULT_DUBBO_CONSUMER_PREFIX = "dubbo:consumer:";
+
+    public static final String DUBBO_INTERFACE_GROUP_VERSION_ENABLED = "csp.sentinel.dubbo.interface.group.version.enabled";
+
+    private static volatile DubboFallback consumerFallback = new DefaultDubboFallback();
+    private static volatile DubboFallback providerFallback = new DefaultDubboFallback();
+    private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser();
+
+    public static boolean isUsePrefix() {
+        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY));
+    }
+
+    public static String getDubboProviderResNamePrefixKey() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(DUBBO_PROVIDER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_PROVIDER_PREFIX;
+        }
+        return null;
+    }
+
+    public static String getDubboConsumerResNamePrefixKey() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(DUBBO_CONSUMER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_CONSUMER_PREFIX;
+        }
+        return null;
+    }
+
+    public static Boolean getDubboInterfaceGroupAndVersionEnabled() {
+        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_INTERFACE_GROUP_VERSION_ENABLED));
+    }
+
+    public static DubboFallback getConsumerFallback() {
+        return consumerFallback;
+    }
+
+    public static void setConsumerFallback(DubboFallback consumerFallback) {
+        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
+        DubboAdapterGlobalConfig.consumerFallback = consumerFallback;
+    }
+
+    public static DubboFallback getProviderFallback() {
+        return providerFallback;
+    }
+
+    public static void setProviderFallback(DubboFallback providerFallback) {
+        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
+        DubboAdapterGlobalConfig.providerFallback = providerFallback;
+    }
+
+    /**
+     * Get the origin parser of Dubbo adapter.
+     *
+     * @return the origin parser
+     * @since 1.8.0
+     */
+    public static DubboOriginParser getOriginParser() {
+        return originParser;
+    }
+
+    /**
+     * Set the origin parser of Dubbo adapter.
+     *
+     * @param originParser the origin parser
+     * @since 1.8.0
+     */
+    public static void setOriginParser(DubboOriginParser originParser) {
+        AssertUtil.notNull(originParser, "originParser cannot be null");
+        DubboAdapterGlobalConfig.originParser = originParser;
+    }
+
+    private DubboAdapterGlobalConfig() {}
+
+}

+ 34 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DefaultDubboOriginParser.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+/**
+ * Default Dubbo origin parser.
+ *
+ * @author jingzian
+ */
+public class DefaultDubboOriginParser implements DubboOriginParser {
+
+    @Override
+    public String parse(Invoker<?> invoker, Invocation invocation) {
+        return DubboUtils.getApplication(invocation, "");
+    }
+
+}

+ 38 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginParser.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.csp.sentinel.context.Context;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+/**
+ * Customized origin parser for Dubbo provider filter.{@link Context#getOrigin()}
+ *
+ * @author jingzian
+ */
+public interface DubboOriginParser {
+
+    /**
+     * Parses the origin (caller) from Dubbo invocation.
+     *
+     * @param invoker    Dubbo invoker
+     * @param invocation Dubbo invocation
+     * @return the parsed origin
+     */
+    String parse(Invoker<?> invoker, Invocation invocation);
+
+}

+ 80 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/DubboTestUtil.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.provider.DemoService;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.lang.reflect.Method;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author lianglin
+ */
+public class DubboTestUtil {
+
+
+    public static Class<?> DEFAULT_TEST_SERVICE = DemoService.class;
+    public static Method DEFAULT_TEST_METHOD_ONE = DEFAULT_TEST_SERVICE.getMethods()[0];
+    public static Method DEFAULT_TEST_METHOD_TWO = DEFAULT_TEST_SERVICE.getMethods()[1];
+
+    public static Invoker getMockInvoker(URL url, Class<?> cls) {
+        Invoker invoker = mock(Invoker.class);
+        when(invoker.getUrl()).thenReturn(url);
+        when(invoker.getInterface()).thenReturn(cls);
+        return invoker;
+    }
+
+    public static Invoker getDefaultMockInvoker() {
+        return getMockInvoker(getDefaultTestURL(), DEFAULT_TEST_SERVICE);
+    }
+
+    public static Invocation getMockInvocation(Method method) {
+        Invocation invocation = mock(Invocation.class);
+        when(invocation.getMethodName()).thenReturn(method.getName());
+        when(invocation.getParameterTypes()).thenReturn(method.getParameterTypes());
+        return invocation;
+    }
+
+    public static Invocation getDefaultMockInvocationOne() {
+        Invocation invocation = mock(Invocation.class);
+        when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_ONE.getName());
+        when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_ONE.getParameterTypes());
+        return invocation;
+    }
+
+    public static Invocation getDefaultMockInvocationTwo() {
+        Invocation invocation = mock(Invocation.class);
+        when(invocation.getMethodName()).thenReturn(DEFAULT_TEST_METHOD_TWO.getName());
+        when(invocation.getParameterTypes()).thenReturn(DEFAULT_TEST_METHOD_TWO.getParameterTypes());
+        return invocation;
+    }
+
+    public static URL getDefaultTestURL() {
+        URL url = URL.valueOf("dubbo://127.0.0.1:2181")
+                .addParameter(CommonConstants.VERSION_KEY, "1.0.0")
+                .addParameter(CommonConstants.GROUP_KEY, "grp1")
+                .addParameter(CommonConstants.INTERFACE_KEY, DEFAULT_TEST_SERVICE.getName());
+        return url;
+    }
+
+
+}

+ 75 - 0
sentinel-adapter/sentinel-apache-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginRegistryTest.java

@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.csp.sentinel.adapter.dubbo.config.DubboAdapterGlobalConfig;
+import com.alibaba.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author tiecheng
+ */
+public class DubboOriginRegistryTest {
+
+    @After
+    public void cleanUp() {
+        DubboAdapterGlobalConfig.setOriginParser(new DefaultDubboOriginParser());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testDefaultOriginParserFail() {
+        DubboAdapterGlobalConfig.getOriginParser().parse(null, null);
+    }
+
+    @Test
+    public void testDefaultOriginParserSuccess() {
+        RpcInvocation invocation = new RpcInvocation();
+        String dubboName = "sentinel";
+        invocation.setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, dubboName);
+        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName, origin);
+    }
+
+    @Test
+    public void testCustomOriginParser() {
+        DubboAdapterGlobalConfig.setOriginParser(new DubboOriginParser() {
+            @Override
+            public String parse(Invoker<?> invoker, Invocation invocation) {
+                return invocation.getAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, "default") + "_" + invocation
+                        .getMethodName();
+            }
+        });
+
+        RpcInvocation invocation = new RpcInvocation();
+        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals("default_null", origin);
+
+        String dubboName = "sentinel";
+        invocation.setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, dubboName);
+        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName + "_null", origin);
+
+        invocation.setMethodName("hello");
+        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName + "_hello", origin);
+    }
+
+}

+ 75 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/README.md

@@ -0,0 +1,75 @@
+# Sentinel Apache Httpclient Adapter
+
+## Introduction
+
+Sentinel provides integration for OkHttp client to enable flow control for web requests.
+
+Add the following dependency in `pom.xml` (if you are using Maven):
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-apache-httpclient-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+We can use the `SentinelApacheHttpClientBuilder` when `CloseableHttpClient` at initialization, for example:
+
+```java
+CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder().build();
+```
+
+If we want to add some additional configurations, we can refer to the following code
+
+```java
+HttpClientBuilder builder = new SentinelApacheHttpClientBuilder();
+//builder Other Definitions
+CloseableHttpClient httpclient = builder.build();
+```
+
+## Configuration
+
+- `SentinelApacheHttpClientConfig` configuration:
+
+| name | description | type | default value |
+|------|------------|------|-------|
+| prefix | customize resource prefix | `String` | `httpclient:` |
+| extractor | customize resource extractor | `ApacheHttpClientResourceExtractor` | `DefaultApacheHttpClientResourceExtractor` |
+| fallback | handle request when it is blocked | `ApacheHttpClientFallback` | `DefaultApacheHttpClientFallback` |
+
+### extractor (resource extractor)
+
+We can define `ApacheHttpClientResourceExtractor` to customize resource extractor replace `DefaultApacheHttpClientResourceExtractor` at `SentinelApacheHttpClientBuilder` default config, for example: httpclient:GET:/httpclient/back/1 ==> httpclient:GET:/httpclient/back/{id}
+
+```java
+SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+    @Override
+    public String extractor(HttpRequestWrapper request) {
+        String contains = "/httpclient/back/";
+        String uri = request.getRequestLine().getUri();
+        if (uri.startsWith(contains)) {
+            uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+        }
+        return request.getMethod() + ":" + uri;
+    }
+});
+CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+```
+
+### fallback (Block handling)
+
+We can define `ApacheHttpClientFallback` at `SentinelApacheHttpClientBuilder` default config, to handle request is blocked according to the actual scenario, for example:
+
+```java
+public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
+
+    @Override
+    public CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e) {
+        // Just wrap and throw the exception.
+        throw new SentinelRpcException(e);
+    }
+}
+```

+ 69 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/pom.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sentinel-adapter</artifactId>
+        <groupId>com.alibaba.csp</groupId>
+        <version>1.8.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sentinel-apache-httpclient-adapter</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <apache.httpclient.version>4.5.6</apache.httpclient.version>
+        <spring.boot.version>2.1.3.RELEASE</spring.boot.version>
+        <spring-test.version>5.1.5.RELEASE</spring-test.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>${apache.httpclient.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>${spring-test.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 76 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientBuilder.java

@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import org.apache.http.HttpException;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpExecutionAware;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.routing.HttpRoute;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.execchain.ClientExecChain;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientBuilder extends HttpClientBuilder {
+
+    private final SentinelApacheHttpClientConfig config;
+
+    public SentinelApacheHttpClientBuilder(){
+        this.config = new SentinelApacheHttpClientConfig();
+    }
+
+    public SentinelApacheHttpClientBuilder(SentinelApacheHttpClientConfig config){
+        this.config = config;
+    }
+
+    @Override
+    protected ClientExecChain decorateMainExec(final ClientExecChain mainExec) {
+        return new ClientExecChain() {
+            @Override
+            public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request,
+                                                 HttpClientContext clientContext, HttpExecutionAware execAware)
+                    throws IOException, HttpException {
+                Entry entry = null;
+                try {
+                    String name = config.getExtractor().extractor(request);
+                    if (!StringUtil.isEmpty(config.getPrefix())) {
+                        name = config.getPrefix() + name;
+                    }
+                    entry = SphU.entry(name, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+                    return mainExec.execute(route, request, clientContext, execAware);
+                } catch (BlockException e) {
+                    return config.getFallback().handle(request, e);
+                } catch (Throwable t) {
+                    Tracer.traceEntry(t, entry);
+                    throw t;
+                } finally {
+                    if (entry != null) {
+                        entry.exit();
+                    }
+                }
+            }
+        };
+    }
+}

+ 59 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfig.java

@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.config;
+
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.DefaultApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback.ApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback.DefaultApacheHttpClientFallback;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientConfig {
+
+    private String prefix = "httpclient:";
+    private ApacheHttpClientResourceExtractor extractor = new DefaultApacheHttpClientResourceExtractor();
+    private ApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public void setPrefix(String prefix) {
+        AssertUtil.notNull(prefix, "prefix cannot be null");
+        this.prefix = prefix;
+    }
+
+    public ApacheHttpClientResourceExtractor getExtractor() {
+        return extractor;
+    }
+
+    public void setExtractor(ApacheHttpClientResourceExtractor extractor) {
+        AssertUtil.notNull(extractor, "extractor cannot be null");
+        this.extractor = extractor;
+    }
+
+    public ApacheHttpClientFallback getFallback() {
+        return fallback;
+    }
+
+    public void setFallback(ApacheHttpClientFallback fallback) {
+        AssertUtil.notNull(fallback, "fallback cannot be null");
+        this.fallback = fallback;
+    }
+}

+ 26 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/ApacheHttpClientResourceExtractor.java

@@ -0,0 +1,26 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor;
+
+import org.apache.http.client.methods.HttpRequestWrapper;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface ApacheHttpClientResourceExtractor {
+
+    String extractor(HttpRequestWrapper request);
+}

+ 29 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/extractor/DefaultApacheHttpClientResourceExtractor.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor;
+
+import org.apache.http.client.methods.HttpRequestWrapper;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultApacheHttpClientResourceExtractor implements ApacheHttpClientResourceExtractor {
+
+    @Override
+    public String extractor(HttpRequestWrapper request) {
+        return request.getRequestLine().getUri();
+    }
+}

+ 33 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallback.java

@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface ApacheHttpClientFallback {
+
+    CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e);
+}

+ 38 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/DefaultApacheHttpClientFallback.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultApacheHttpClientFallback implements ApacheHttpClientFallback {
+
+    @Override
+    public CloseableHttpResponse handle(HttpRequestWrapper request, BlockException e) {
+        // Just wrap and throw the exception.
+        throw new SentinelRpcException(e);
+    }
+}

+ 109 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/SentinelApacheHttpClientTest.java

@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.app.TestApplication;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.config.SentinelApacheHttpClientConfig;
+import com.alibaba.csp.sentinel.adapter.apache.httpclient.extractor.ApacheHttpClientResourceExtractor;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author zhaoyuguang
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class,
+        webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+        properties = {
+                "server.port=8084"
+        })
+public class SentinelApacheHttpClientTest {
+
+    @Value("${server.port}")
+    private Integer port;
+
+    @Test
+    public void testSentinelOkHttpInterceptor0() throws Exception {
+
+        CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder().build();
+
+        HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back");
+        System.out.println(getRemoteString(httpclient, httpGet));
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode("httpclient:/httpclient/back");
+        assertNotNull(cn);
+        Constants.ROOT.removeChildList();
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+    }
+
+    @Test
+    public void testSentinelOkHttpInterceptor1() throws Exception {
+        SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+        config.setExtractor(new ApacheHttpClientResourceExtractor() {
+
+            @Override
+            public String extractor(HttpRequestWrapper request) {
+                String contains = "/httpclient/back/";
+                String uri = request.getRequestLine().getUri();
+                if (uri.startsWith(contains)) {
+                    uri = uri.substring(0, uri.indexOf(contains) + contains.length()) + "{id}";
+                }
+                return request.getMethod() + ":" + uri;
+            }
+        });
+        CloseableHttpClient httpclient = new SentinelApacheHttpClientBuilder(config).build();
+
+        HttpGet httpGet = new HttpGet("http://localhost:" + port + "/httpclient/back/1");
+        System.out.println(getRemoteString(httpclient, httpGet));
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode("httpclient:GET:/httpclient/back/{id}");
+        assertNotNull(cn);
+        Constants.ROOT.removeChildList();
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+    }
+
+    private String getRemoteString(CloseableHttpClient httpclient, HttpGet httpGet) throws IOException {
+        String result;
+        HttpContext context = new BasicHttpContext();
+        CloseableHttpResponse response;
+        response = httpclient.execute(httpGet, context);
+        try {
+            HttpEntity entity = response.getEntity();
+            result = EntityUtils.toString(entity, "utf-8");
+            EntityUtils.consume(entity);
+        } finally {
+            response.close();
+        }
+        httpclient.close();
+        return result;
+    }
+}

+ 30 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/TestApplication.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author zhaoyuguang
+ */
+@SpringBootApplication
+public class TestApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(TestApplication.class);
+    }
+}

+ 37 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/app/controller/TestController.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.app.controller;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author zhaoyuguang
+ */
+@RestController
+public class TestController {
+
+    @RequestMapping("/httpclient/back")
+    public String back() {
+        return "Welcome Back!";
+    }
+
+    @RequestMapping("/httpclient/back/{id}")
+    public String back(@PathVariable String id) {
+        return "Welcome Back! " + id;
+    }
+}

+ 42 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/config/SentinelApacheHttpClientConfigTest.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.config;
+
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelApacheHttpClientConfigTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigSetPrefix() {
+        SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+        config.setPrefix(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigSetCleaner() {
+        SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+        config.setExtractor(null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigSetFallback() {
+        SentinelApacheHttpClientConfig config = new SentinelApacheHttpClientConfig();
+        config.setFallback(null);
+    }
+}

+ 34 - 0
sentinel-adapter/sentinel-apache-httpclient-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/apache/httpclient/fallback/ApacheHttpClientFallbackTest.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.apache.httpclient.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class ApacheHttpClientFallbackTest {
+
+    @Test(expected = SentinelRpcException.class)
+    public void testDefaultOkHttpFallback() {
+        BlockException e = new FlowException("xxx");
+        ApacheHttpClientFallback fallback = new DefaultApacheHttpClientFallback();
+        fallback.handle(null, e);
+    }
+}

+ 1 - 0
sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.slotchain.ProcessorSlot

@@ -0,0 +1 @@
+com.alibaba.csp.sentinel.adapter.gateway.common.slot.GatewayFlowSlot

+ 108 - 0
sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/DubboAdapterGlobalConfig.java

@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.dubbo;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DefaultDubboFallback;
+import com.alibaba.csp.sentinel.adapter.dubbo.fallback.DubboFallback;
+import com.alibaba.csp.sentinel.adapter.dubbo.origin.DefaultDubboOriginParser;
+import com.alibaba.csp.sentinel.adapter.dubbo.origin.DubboOriginParser;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+/**
+ * <p>Global config and callback registry of Dubbo legacy adapter.</p>
+ *
+ * @author lianglin
+ * @author Eric Zhao
+ * @since 1.7.0
+ */
+public final class DubboAdapterGlobalConfig {
+
+    private static final String TRUE_STR = "true";
+
+    public static final String DUBBO_RES_NAME_WITH_PREFIX_KEY = "csp.sentinel.dubbo.resource.use.prefix";
+    public static final String DUBBO_PROVIDER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.provider.prefix";
+    public static final String DUBBO_CONSUMER_RES_NAME_PREFIX_KEY = "csp.sentinel.dubbo.resource.consumer.prefix";
+
+    private static final String DEFAULT_DUBBO_PROVIDER_PREFIX = "dubbo:provider:";
+    private static final String DEFAULT_DUBBO_CONSUMER_PREFIX = "dubbo:consumer:";
+
+    private static volatile DubboFallback consumerFallback = new DefaultDubboFallback();
+    private static volatile DubboFallback providerFallback = new DefaultDubboFallback();
+    private static volatile DubboOriginParser originParser = new DefaultDubboOriginParser();
+
+    public static boolean isUsePrefix() {
+        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(DUBBO_RES_NAME_WITH_PREFIX_KEY));
+    }
+
+    public static String getDubboProviderPrefix() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(DUBBO_PROVIDER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_PROVIDER_PREFIX;
+        }
+        return null;
+    }
+
+    public static String getDubboConsumerPrefix() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(DUBBO_CONSUMER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_DUBBO_CONSUMER_PREFIX;
+        }
+        return null;
+    }
+
+    public static DubboFallback getConsumerFallback() {
+        return consumerFallback;
+    }
+
+    public static void setConsumerFallback(DubboFallback consumerFallback) {
+        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
+        DubboAdapterGlobalConfig.consumerFallback = consumerFallback;
+    }
+
+    public static DubboFallback getProviderFallback() {
+        return providerFallback;
+    }
+
+    public static void setProviderFallback(DubboFallback providerFallback) {
+        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
+        DubboAdapterGlobalConfig.providerFallback = providerFallback;
+    }
+
+    /**
+     * Get the origin parser of Dubbo adapter.
+     *
+     * @return the origin parser
+     * @since 1.8.0
+     */
+    public static DubboOriginParser getOriginParser() {
+        return originParser;
+    }
+
+    /**
+     * Set the origin parser of Dubbo adapter.
+     *
+     * @param originParser the origin parser
+     * @since 1.8.0
+     */
+    public static void setOriginParser(DubboOriginParser originParser) {
+        AssertUtil.notNull(originParser, "originParser cannot be null");
+        DubboAdapterGlobalConfig.originParser = originParser;
+    }
+
+    private DubboAdapterGlobalConfig() {}
+}

+ 35 - 0
sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DefaultDubboOriginParser.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+
+/**
+ * Default Dubbo origin parser.
+ *
+ * @author tiecheng
+ * @since 1.8.0
+ */
+public class DefaultDubboOriginParser implements DubboOriginParser {
+
+    @Override
+    public String parse(Invoker<?> invoker, Invocation invocation) {
+        return DubboUtils.getApplication(invocation, "");
+    }
+
+}

+ 38 - 0
sentinel-adapter/sentinel-dubbo-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginParser.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+
+/**
+ * Customized origin parser for Dubbo provider filter.
+ *
+ * @author tiecheng
+ * @since 1.8.0
+ */
+public interface DubboOriginParser {
+
+    /**
+     * Parses the origin (caller) from Dubbo invocation.
+     *
+     * @param invoker    Dubbo invoker
+     * @param invocation Dubbo invocation
+     * @return the parsed origin
+     */
+    String parse(Invoker<?> invoker, Invocation invocation);
+
+}

+ 76 - 0
sentinel-adapter/sentinel-dubbo-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/dubbo/origin/DubboOriginRegistryTest.java

@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.dubbo.origin;
+
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboAdapterGlobalConfig;
+import com.alibaba.csp.sentinel.adapter.dubbo.DubboUtils;
+import com.alibaba.dubbo.rpc.Invocation;
+import com.alibaba.dubbo.rpc.Invoker;
+import com.alibaba.dubbo.rpc.RpcInvocation;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author tiecheng
+ */
+public class DubboOriginRegistryTest {
+
+    @After
+    public void cleanUp() {
+        DubboAdapterGlobalConfig.setOriginParser(new DefaultDubboOriginParser());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testDefaultOriginParserFail() {
+        DubboAdapterGlobalConfig.getOriginParser().parse(null, null);
+    }
+
+    @Test
+    public void testDefaultOriginParserSuccess() {
+        RpcInvocation invocation = new RpcInvocation();
+        String dubboName = "sentinel";
+        invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName);
+        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName, origin);
+    }
+
+    @Test
+    public void testCustomOriginParser() {
+        DubboAdapterGlobalConfig.setOriginParser(new DubboOriginParser() {
+            @Override
+            public String parse(Invoker<?> invoker, Invocation invocation) {
+                return invocation.getAttachment(DubboUtils.DUBBO_APPLICATION_KEY, "default") + "_" + invocation
+                    .getMethodName();
+            }
+        });
+
+        RpcInvocation invocation = new RpcInvocation();
+        String origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals("default_null", origin);
+
+        String dubboName = "sentinel";
+        invocation.setAttachment(DubboUtils.DUBBO_APPLICATION_KEY, dubboName);
+        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName + "_null", origin);
+
+        invocation.setMethodName("hello");
+        origin = DubboAdapterGlobalConfig.getOriginParser().parse(null, invocation);
+        Assert.assertEquals(dubboName + "_hello", origin);
+    }
+
+}

+ 83 - 0
sentinel-adapter/sentinel-jax-rs-adapter/README.md

@@ -0,0 +1,83 @@
+# Sentinel adapter for JAX-RS
+
+Sentinel provides integration to enable fault-tolerance and flow control for JAX-RS web requests.
+Add the following dependency in `pom.xml` (if you are using Maven):
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-jax-rs-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+## SentinelJaxRsProviderFilter
+
+The `SentinelJaxRsProviderFilter` is auto activated in pure JAX-RS application.
+
+For Spring web applications you can configure with Spring bean:
+
+```java
+@Configuration
+public class FilterConfig {
+
+    @Bean
+    public SentinelJaxRsProviderFilter sentinelJaxRsProviderFilter() {
+        return new SentinelJaxRsProviderFilter();
+    }
+}
+```
+
+## DefaultExceptionMapper
+
+Sentinel provides DefaultExceptionMapper to map Throwable to Response (with Status.INTERNAL_SERVER_ERROR),
+in order to let SentinelJaxRsProviderFilter to be called and exit the Sentinel entry.
+
+According to `3.3.4 Exceptions` of [jaxrs-2_1-final-spec](https://download.oracle.com/otn-pub/jcp/jaxrs-2_1-final-eval-spec/jaxrs-2_1-final-spec.pdf):
+
+> Checked exceptions and throwables that have not been mapped and cannot be thrown directly MUST be wrapped in a container-specific exception that is then thrown and allowed to propagate to the underlying container.
+
+If WebApplicationException or its subclasses are thrown, they'll be automatically converted to `Response` and can enter response filter.
+If other kind of exceptions were thrown, and not matched by custom exception mapper, then the response filter cannot be called.
+For this case, a default exception mapper maybe introduced.
+
+According to `4.4 Exception Mapping Providers` of [jaxrs-2_1-final-spec](https://download.oracle.com/otn-pub/jcp/jaxrs-2_1-final-eval-spec/jaxrs-2_1-final-spec.pdf):
+
+> When choosing an exception mapping provider to map an exception,  an implementation MUST use the provider whose generic type is the nearest superclass of the exception.  If two or more exception providers are applicable, the one with the highest priority MUST be chosen as described in Section 4.1.3.
+
+If user also provides customized exception mapper of `Throwable`, then user has the responsibility to convert it to response and then the response filter can be called.
+
+As describe in `6.7.1 exceptions` of [jaxrs-2_1-final-spec](https://download.oracle.com/otn-pub/jcp/jaxrs-2_1-final-eval-spec/jaxrs-2_1-final-spec.pdf):
+
+> A response mapped from an exception MUST be processed using the ContainerResponse filter chain and the WriteTo interceptor chain (if an entity is present in the mapped response).
+
+## SentinelJaxRsClientTemplate
+
+For jax-rs client, we provide `SentinelJaxRsClientTemplate` you can use it like this:
+
+```
+Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+    @Override
+    public Response get() {
+        return client.target(host).path(url).request()
+                .get();
+    }
+});
+```
+
+or executeAsync like this:
+
+```
+Future<Response> future = SentinelJaxRsClientTemplate.executeAsync(resourceName, new Supplier<Future<Response>>() {
+    @Override
+    public Future<Response> get() {
+        return client.target(host).path(url).request()
+                .async()
+                .get();
+    }
+});
+```
+
+When a request is blocked, Sentinel JAX-RS filter will return Response with status of `TOO_MANY_REQUESTS` indicating the request is rejected.
+
+You can customize it by implement your own `SentinelJaxRsFallback` and register to `SentinelJaxRsConfig`.

+ 74 - 0
sentinel-adapter/sentinel-jax-rs-adapter/pom.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-adapter</artifactId>
+        <version>1.8.3</version>
+    </parent>
+
+    <artifactId>sentinel-jax-rs-adapter</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <javax.ws.rs-api.version>2.1.1</javax.ws.rs-api.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+            <version>${javax.ws.rs-api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>2.2.6.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>2.2.6.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <version>4.3.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-spring-boot-starter</artifactId>
+            <version>4.5.1.Final</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <forkMode>always</forkMode>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 79 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsClientTemplate.java

@@ -0,0 +1,79 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig;
+import com.alibaba.csp.sentinel.adapter.jaxrs.future.FutureWrapper;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.function.Supplier;
+
+import javax.ws.rs.core.Response;
+import java.util.concurrent.Future;
+
+
+/**
+ * wrap jax-rs client execution with sentinel
+ * <pre>
+ *         Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+ *
+ *             @Override
+ *             public Response get() {
+ *                 return client.target(host).path(url).request()
+ *                         .get();
+ *             }
+ *         });
+ * </pre>
+ * @author sea
+ */
+public class SentinelJaxRsClientTemplate {
+
+    /**
+     * execute supplier with sentinel
+     * @param resourceName
+     * @param supplier
+     * @return
+     */
+    public static Response execute(String resourceName, Supplier<Response> supplier) {
+        Entry entry = null;
+        try {
+            entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+            return supplier.get();
+        } catch (BlockException ex) {
+            return SentinelJaxRsConfig.getJaxRsFallback().fallbackResponse(resourceName, ex);
+        } finally {
+            System.out.println("entry exit");
+            if (entry != null) {
+                entry.exit();
+            }
+        }
+    }
+
+    /**
+     * execute supplier with sentinel
+     * @param resourceName
+     * @param supplier
+     * @return
+     */
+    public static Future<Response> executeAsync(String resourceName, Supplier<Future<Response>> supplier) {
+        try {
+            AsyncEntry entry = SphU.asyncEntry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+            return new FutureWrapper<>(entry, supplier.get());
+        } catch (BlockException ex) {
+            return SentinelJaxRsConfig.getJaxRsFallback().fallbackFutureResponse(resourceName, ex);
+        }
+    }
+}

+ 88 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsProviderFilter.java

@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import javax.ws.rs.container.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.Provider;
+import java.io.IOException;
+
+/**
+ * @author sea
+ */
+@Provider
+public class SentinelJaxRsProviderFilter implements ContainerRequestFilter, ContainerResponseFilter {
+
+    private static final String SENTINEL_JAX_RS_PROVIDER_CONTEXT_NAME = "sentinel_jax_rs_provider_context";
+
+
+    private static final String SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY = "sentinel_jax_rs_provider_entry_property";
+
+    @Context
+    private ResourceInfo resourceInfo;
+
+    @Override
+    public void filter(ContainerRequestContext containerRequestContext) throws IOException {
+
+        try {
+            String resourceName = getResourceName(containerRequestContext, resourceInfo);
+
+            if (StringUtil.isNotEmpty(resourceName)) {
+                // Parse the request origin using registered origin parser.
+                String origin = parseOrigin(containerRequestContext);
+                String contextName = getContextName(containerRequestContext);
+                ContextUtil.enter(contextName, origin);
+                Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
+
+                containerRequestContext.setProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY, entry);
+            }
+        } catch (BlockException e) {
+            try {
+                containerRequestContext.abortWith(SentinelJaxRsConfig.getJaxRsFallback().fallbackResponse(containerRequestContext.getUriInfo().getPath(), e));
+            } finally {
+                ContextUtil.exit();
+            }
+        }
+    }
+
+    @Override
+    public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
+        Entry entry = (Entry) containerRequestContext.getProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY);
+        if (entry != null) {
+            entry.exit();
+        }
+        containerRequestContext.removeProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY);
+        ContextUtil.exit();
+    }
+
+    public String getResourceName(ContainerRequestContext containerRequestContext, ResourceInfo resourceInfo) {
+        return SentinelJaxRsConfig.getResourceNameParser().parse(containerRequestContext, resourceInfo);
+    }
+
+    protected String getContextName(ContainerRequestContext request) {
+        return SENTINEL_JAX_RS_PROVIDER_CONTEXT_NAME;
+    }
+
+    protected String parseOrigin(ContainerRequestContext request) {
+        return SentinelJaxRsConfig.getRequestOriginParser().parseOrigin(request);
+    }
+}

+ 62 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/config/SentinelJaxRsConfig.java

@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.config;
+
+import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.DefaultSentinelJaxRsFallback;
+import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.SentinelJaxRsFallback;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.DefaultRequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.DefaultResourceNameParser;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.RequestOriginParser;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.ResourceNameParser;
+
+/**
+ *  @author sea
+ */
+public class SentinelJaxRsConfig {
+
+    private static volatile ResourceNameParser resourceNameParser = new DefaultResourceNameParser();
+
+    private static volatile RequestOriginParser requestOriginParser = new DefaultRequestOriginParser();
+
+    private static volatile SentinelJaxRsFallback jaxRsFallback = new DefaultSentinelJaxRsFallback();
+
+    public static ResourceNameParser getResourceNameParser() {
+        return resourceNameParser;
+    }
+
+    public static void setResourceNameParser(ResourceNameParser resourceNameParser) {
+        SentinelJaxRsConfig.resourceNameParser = resourceNameParser;
+    }
+
+    public static RequestOriginParser getRequestOriginParser() {
+        return requestOriginParser;
+    }
+
+    public static void setRequestOriginParser(RequestOriginParser originParser) {
+        SentinelJaxRsConfig.requestOriginParser = originParser;
+    }
+
+    public static SentinelJaxRsFallback getJaxRsFallback() {
+        return jaxRsFallback;
+    }
+
+    public static void setJaxRsFallback(SentinelJaxRsFallback jaxRsFallback) {
+        SentinelJaxRsConfig.jaxRsFallback = jaxRsFallback;
+    }
+
+    private SentinelJaxRsConfig() {
+    }
+}

+ 39 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/exception/DefaultExceptionMapper.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.exception;
+
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * sentinel jax-rs adapter provide this exception mapper
+ * in case of user throw exception which is not {@link javax.ws.rs.WebApplicationException} and not matched by any ExceptionMapper
+ * this exception mapper convert exception to Response let ContainerResponseFilter to be called to exit sentinel entry
+ * user can add custom ExceptionMapper and config with {@link javax.annotation.Priority} with lower value
+ * @author sea
+ */
+@Provider
+public class DefaultExceptionMapper implements ExceptionMapper<Throwable> {
+
+    @Override
+    public Response toResponse(Throwable exception) {
+        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+                .entity(exception.getMessage())
+                .build();
+    }
+}

+ 45 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/fallback/DefaultSentinelJaxRsFallback.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.fallback;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+/**
+ * @author sea
+ */
+public class DefaultSentinelJaxRsFallback implements SentinelJaxRsFallback {
+    @Override
+    public Response fallbackResponse(String route, Throwable cause) {
+        return Response.status(Response.Status.TOO_MANY_REQUESTS)
+                .entity("Blocked by Sentinel (flow limiting)")
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .build();
+    }
+
+    @Override
+    public Future<Response> fallbackFutureResponse(final String route, final Throwable cause) {
+        return new FutureTask<>(new Callable<Response>() {
+            @Override
+            public Response call() throws Exception {
+                return fallbackResponse(route, cause);
+            }
+        });
+    }
+}

+ 43 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/fallback/SentinelJaxRsFallback.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.fallback;
+
+import javax.ws.rs.core.Response;
+import java.util.concurrent.Future;
+
+/**
+ * @author sea
+ */
+public interface SentinelJaxRsFallback {
+
+    /**
+     * Provides a fallback response based on the cause of the failed execution.
+     *
+     * @param route The route the fallback is for
+     * @param cause cause of the main method failure, may be <code>null</code>
+     * @return the fallback response
+     */
+    Response fallbackResponse(String route, Throwable cause);
+
+    /**
+     * Provides a fallback response future based on the cause of the failed execution.
+     *
+     * @param route The route the fallback is for
+     * @param cause cause of the main method failure, may be <code>null</code>
+     * @return the fallback response future
+     */
+    Future<Response> fallbackFutureResponse(String route, Throwable cause);
+}

+ 81 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/future/FutureWrapper.java

@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.future;
+
+import com.alibaba.csp.sentinel.AsyncEntry;
+
+import java.util.concurrent.*;
+
+/**
+ * wrap Future to ensure entry exit
+ * @author sea
+ */
+public class FutureWrapper<V> implements Future<V> {
+
+    AsyncEntry entry;
+
+    Future<V> future;
+
+    public FutureWrapper(AsyncEntry entry, Future<V> future) {
+        this.entry = entry;
+        this.future = future;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        try {
+            return future.cancel(mayInterruptIfRunning);
+        } finally {
+            exitEntry();
+        }
+
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return future.isCancelled();
+    }
+
+    @Override
+    public boolean isDone() {
+        return future.isDone();
+    }
+
+    @Override
+    public V get() throws InterruptedException, ExecutionException {
+        try {
+            return future.get();
+        } finally {
+            exitEntry();
+        }
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+        try {
+            return future.get(timeout, unit);
+        } finally {
+            exitEntry();
+        }
+    }
+
+    private void exitEntry() {
+        if (entry != null) {
+            entry.exit();
+        }
+    }
+
+}

+ 31 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/DefaultRequestOriginParser.java

@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.request;
+
+import javax.ws.rs.container.ContainerRequestContext;
+
+/**
+ * @author sea
+ */
+public class DefaultRequestOriginParser implements RequestOriginParser {
+
+    private static final String EMPTY_ORIGIN = "";
+
+    @Override
+    public String parseOrigin(ContainerRequestContext request) {
+        return EMPTY_ORIGIN;
+    }
+}

+ 33 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/DefaultResourceNameParser.java

@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.request;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ResourceInfo;
+
+/**
+ * @author sea
+ */
+public class DefaultResourceNameParser implements ResourceNameParser {
+    @Override
+    public String parse(ContainerRequestContext containerRequestContext, ResourceInfo resourceInfo) {
+        Path classPath = resourceInfo.getResourceClass().getAnnotation(Path.class);
+        Path methodPath = resourceInfo.getResourceMethod().getAnnotation(Path.class);
+        return containerRequestContext.getRequest().getMethod() + ":" + (classPath != null ? classPath.value() : "") + (methodPath != null ? methodPath.value() : "");
+    }
+
+}

+ 34 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/RequestOriginParser.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.request;
+
+import javax.ws.rs.container.ContainerRequestContext;
+
+/**
+ * The origin parser parses request origin (e.g. IP, user, appName) from HTTP request.
+ *
+ * @author sea
+ */
+public interface RequestOriginParser {
+
+    /**
+     * Parse the origin from given HTTP request.
+     *
+     * @param request HTTP request
+     * @return parsed origin
+     */
+    String parseOrigin(ContainerRequestContext request);
+}

+ 27 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/request/ResourceNameParser.java

@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs.request;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ResourceInfo;
+
+/**
+ * @author sea
+ */
+public interface ResourceNameParser {
+
+    String parse(ContainerRequestContext containerRequestContext, ResourceInfo resourceInfo);
+}

+ 413 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/ClientFilterTest.java

@@ -0,0 +1,413 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.CtSph;
+import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig;
+import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.SentinelJaxRsFallback;
+import com.alibaba.csp.sentinel.context.Context;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.EntranceNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import com.alibaba.csp.sentinel.util.function.Supplier;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.util.SocketUtils;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.concurrent.*;
+
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertNull;
+
+/**
+ * @author sea
+ */
+public class ClientFilterTest {
+
+    private static final String HELLO_STR = "Hello!";
+
+    static int port;
+
+    static String host;
+
+    static Client client;
+
+    static ConfigurableApplicationContext ctx;
+
+    @BeforeClass
+    public static void startApplication() {
+        client = ClientBuilder.newBuilder()
+                .connectTimeout(3, TimeUnit.SECONDS)
+                .readTimeout(3, TimeUnit.SECONDS)
+                .build();
+
+        port = SocketUtils.findAvailableTcpPort();
+        host = "http://127.0.0.1:" + port;
+        SpringApplication springApplication = new SpringApplication(TestApplication.class);
+        ctx = springApplication.run("--spring.profiles.active=client", "--server.port=" + port);
+    }
+
+    @AfterClass
+    public static void shutdown() {
+        ctx.close();
+
+        Context context = ContextUtil.getContext();
+        if (context != null) {
+            context.setCurEntry(null);
+            ContextUtil.exit();
+        }
+
+        Constants.ROOT.removeChildList();
+
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+
+        // Clear chainMap in CtSph
+        try {
+            Method resetChainMapMethod = CtSph.class.getDeclaredMethod("resetChainMap");
+            resetChainMapMethod.setAccessible(true);
+            resetChainMapMethod.invoke(null);
+        } catch (Exception e) {
+            // Empty
+        }
+    }
+
+    @After
+    public void cleanUp() {
+        FlowRuleManager.loadRules(null);
+        ClusterBuilderSlot.resetClusterNodes();
+    }
+
+    @Test
+    public void testClientGetHello() {
+        final String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+
+            @Override
+            public Response get() {
+                return client.target(host).path(url).request()
+                        .get();
+            }
+        });
+        assertEquals(200, response.getStatus());
+        assertEquals(HELLO_STR, response.readEntity(String.class));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+
+        String context = "";
+        for (Node n : Constants.ROOT.getChildList()) {
+            if (n instanceof EntranceNode) {
+                String id = ((EntranceNode) n).getId().getName();
+                if (url.equals(id)) {
+                    context = ((EntranceNode) n).getId().getName();
+                }
+            }
+        }
+        assertEquals("", context);
+    }
+
+    @Test
+    public void testClientAsyncGetHello() throws InterruptedException, ExecutionException {
+        final String url = "/test/async-hello";
+        final String resourceName = "GET:" + url;
+
+        Future<Response> future = SentinelJaxRsClientTemplate.executeAsync(resourceName, new Supplier<Future<Response>>() {
+            @Override
+            public Future<Response> get() {
+                return client.target(host).path(url).request()
+                        .async()
+                        .get();
+            }
+        });
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(HELLO_STR, future.get().readEntity(String.class));
+
+        cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCustomResourceName() {
+        final String url = "/test/hello/{name}";
+        final String resourceName = "GET:" + url;
+
+        Response response1 = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host)
+                        .path(url)
+                        .resolveTemplate("name", "abc")
+                        .request()
+                        .get();
+            }
+        });
+        assertEquals(200, response1.getStatus());
+        assertEquals("Hello abc !", response1.readEntity(String.class));
+
+        Response response2 = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host)
+                        .path(url)
+                        .resolveTemplate("name", "def")
+                        .request()
+                        .get();
+            }
+        });
+        assertEquals(javax.ws.rs.core.Response.Status.OK.getStatusCode(), response2.getStatus());
+        assertEquals("Hello def !", response2.readEntity(String.class));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(2, cn.passQps(), 0.01);
+
+        assertNull(ClusterBuilderSlot.getClusterNode("/test/hello/abc"));
+        assertNull(ClusterBuilderSlot.getClusterNode("/test/hello/def"));
+    }
+
+    @Test
+    public void testClientFallback() {
+        final String url = "/test/hello";
+        final String resourceName = "GET:" + url;
+        configureRulesFor(resourceName, 0);
+
+        Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host).path(url).request()
+                        .get();
+            }
+        });
+        assertEquals(javax.ws.rs.core.Response.Status.TOO_MANY_REQUESTS.getStatusCode(), response.getStatus());
+        assertEquals("Blocked by Sentinel (flow limiting)", response.readEntity(String.class));
+
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testClientCustomFallback() {
+        final String url = "/test/hello";
+        final String resourceName = "GET:" + url;
+        configureRulesFor(resourceName, 0);
+
+        SentinelJaxRsConfig.setJaxRsFallback(new SentinelJaxRsFallback() {
+            @Override
+            public javax.ws.rs.core.Response fallbackResponse(String route, Throwable cause) {
+                return javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.OK)
+                        .entity("Blocked by Sentinel (flow limiting)")
+                        .type(MediaType.APPLICATION_JSON_TYPE)
+                        .build();
+            }
+
+            @Override
+            public Future<Response> fallbackFutureResponse(final String route, final Throwable cause) {
+                return new FutureTask<>(new Callable<Response>() {
+                    @Override
+                    public Response call() throws Exception {
+                        return fallbackResponse(route, cause);
+                    }
+                });
+            }
+        });
+
+        Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host).path(url).request()
+                        .get();
+            }
+        });
+        assertEquals(javax.ws.rs.core.Response.Status.OK.getStatusCode(), response.getStatus());
+        assertEquals("Blocked by Sentinel (flow limiting)", response.readEntity(String.class));
+
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testServerReturn400() {
+        final String url = "/test/400";
+        final String resourceName = "GET:" + url;
+        Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host).path(url).request()
+                        .get();
+            }
+        });
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+        assertEquals("test return 400", response.readEntity(String.class));
+
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testServerReturn500() {
+        final String url = "/test/ex";
+        final String resourceName = "GET:" + url;
+        Response response = SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+            @Override
+            public Response get() {
+                return client.target(host).path(url).request()
+                        .get();
+            }
+        });
+        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
+        assertEquals("test exception mapper", response.readEntity(String.class));
+
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testServerTimeout() {
+        final String url = "/test/delay/10";
+        final String resourceName = "GET:/test/delay/{seconds}";
+        try {
+            SentinelJaxRsClientTemplate.execute(resourceName, new Supplier<Response>() {
+                @Override
+                public Response get() {
+                    return client.target(host).path(url).request()
+                            .get();
+                }
+            });
+        } catch (ProcessingException e) {
+            //ignore
+        }
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testFutureGetServerTimeout() {
+        final String url = "/test/delay/10";
+        final String resourceName = "GET:/test/delay/{seconds}";
+        try {
+            Future<Response> future = SentinelJaxRsClientTemplate.executeAsync(resourceName, new Supplier<Future<Response>>() {
+                @Override
+                public Future<Response> get() {
+                    return client.target(host).path(url).request()
+                            .async()
+                            .get();
+                }
+            });
+            future.get();
+        } catch (Exception e) {
+            //ignore
+        }
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testFutureGetTimeout() {
+        final String url = "/test/delay/10";
+        final String resourceName = "GET:/test/delay/{seconds}";
+        try {
+            Future<Response> future = SentinelJaxRsClientTemplate.executeAsync(resourceName, new Supplier<Future<Response>>() {
+                @Override
+                public Future<Response> get() {
+                    return client.target(host).path(url).request()
+                            .async()
+                            .get();
+                }
+            });
+            future.get(1, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            //ignore
+        }
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCancelFuture() {
+        final String url = "/test/delay/10";
+        final String resourceName = "GET:/test/delay/{seconds}";
+        try {
+            Future<Response> future = SentinelJaxRsClientTemplate.executeAsync(resourceName, new Supplier<Future<Response>>() {
+                @Override
+                public Future<Response> get() {
+                    return client.target(host).path(url).request()
+                            .async()
+                            .get();
+                }
+            });
+            future.cancel(false);
+        } catch (Exception e) {
+            //ignore
+        }
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+    }
+
+    private void configureRulesFor(String resource, int count) {
+        configureRulesFor(resource, count, "default");
+    }
+
+    private void configureRulesFor(String resource, int count, String limitApp) {
+        FlowRule rule = new FlowRule()
+                .setCount(count)
+                .setGrade(RuleConstant.FLOW_GRADE_QPS);
+        rule.setResource(resource);
+        if (StringUtil.isNotBlank(limitApp)) {
+            rule.setLimitApp(limitApp);
+        }
+        FlowRuleManager.loadRules(Collections.singletonList(rule));
+    }
+}

+ 257 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/ProviderFilterTest.java

@@ -0,0 +1,257 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import java.util.Collections;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig;
+import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.SentinelJaxRsFallback;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.RequestOriginParser;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.EntranceNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.util.SocketUtils;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.MediaType;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.*;
+
+/**
+ * @author sea
+ */
+public class ProviderFilterTest {
+
+    private static final String HELLO_STR = "Hello!";
+
+    static ConfigurableApplicationContext ctx;
+
+    @BeforeClass
+    public static void startApplication() {
+        RestAssured.basePath = "";
+        int port = SocketUtils.findAvailableTcpPort();
+        RestAssured.port = port;
+        SpringApplication springApplication = new SpringApplication(TestApplication.class);
+        ctx = springApplication.run("--spring.profiles.active=provider", "--server.port=" + port);
+    }
+
+    @AfterClass
+    public static void shutdown() {
+        ctx.close();
+    }
+
+    @After
+    public void cleanUp() {
+        FlowRuleManager.loadRules(null);
+        ClusterBuilderSlot.resetClusterNodes();
+    }
+
+
+    @Test
+    public void testGetHello() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+
+        String context = "";
+        for (Node n : Constants.ROOT.getChildList()) {
+            if (n instanceof EntranceNode) {
+                String id = ((EntranceNode) n).getId().getName();
+                if (url.equals(id)) {
+                    context = ((EntranceNode) n).getId().getName();
+                }
+            }
+        }
+        assertEquals("", context);
+    }
+
+    @Test
+    public void testAsyncGetHello() {
+        String url = "/test/async-hello";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+
+        String context = "";
+        for (Node n : Constants.ROOT.getChildList()) {
+            if (n instanceof EntranceNode) {
+                String id = ((EntranceNode) n).getId().getName();
+                if (url.equals(id)) {
+                    context = ((EntranceNode) n).getId().getName();
+                }
+            }
+        }
+        assertEquals("", context);
+    }
+
+    @Test
+    public void testUrlPathParam() {
+        String url = "/test/hello/{name}";
+        String resourceName = "GET:" + url;
+
+        String url1 = "/test/hello/abc";
+        Response response1 = given().get(url1);
+        response1.then().statusCode(200).body(equalTo("Hello abc !"));
+
+        String url2 = "/test/hello/def";
+        Response response2 = given().get(url2);
+        response2.then().statusCode(200).body(equalTo("Hello def !"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(2, cn.passQps(), 0.01);
+
+        assertNull(ClusterBuilderSlot.getClusterNode("GET:" + url1));
+        assertNull(ClusterBuilderSlot.getClusterNode("GET:" + url2));
+    }
+
+    @Test
+    public void testDefaultFallback() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        configureRulesFor(resourceName, 0);
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.TOO_MANY_REQUESTS.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCustomFallback() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        SentinelJaxRsConfig.setJaxRsFallback(new SentinelJaxRsFallback() {
+            @Override
+            public javax.ws.rs.core.Response fallbackResponse(String route, Throwable cause) {
+                return javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.OK)
+                        .entity("Blocked by Sentinel (flow limiting)")
+                        .type(MediaType.APPLICATION_JSON_TYPE)
+                        .build();
+            }
+
+            @Override
+            public Future<javax.ws.rs.core.Response> fallbackFutureResponse(final String route, final Throwable cause) {
+                return new FutureTask<>(new Callable<javax.ws.rs.core.Response>() {
+                    @Override
+                    public javax.ws.rs.core.Response call() throws Exception {
+                        return fallbackResponse(route, cause);
+                    }
+                });
+            }
+        });
+
+
+        configureRulesFor(resourceName, 0);
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.OK.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCustomRequestOriginParser() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+
+        String limitOrigin = "appB";
+        final String headerName = "X-APP";
+        configureRulesFor(resourceName, 0, limitOrigin);
+
+        SentinelJaxRsConfig.setRequestOriginParser(new RequestOriginParser() {
+            @Override
+            public String parseOrigin(ContainerRequestContext request) {
+                String origin = request.getHeaderString(headerName);
+                return origin != null ? origin : "";
+            }
+        });
+
+        Response response = given()
+                .header(headerName, "appA").get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        Response blockedResp = given()
+                .header(headerName, "appB")
+                .get(url);
+        blockedResp.then().statusCode(javax.ws.rs.core.Response.Status.TOO_MANY_REQUESTS.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+        assertEquals(1, cn.blockQps(), 0.01);
+    }
+
+    @Test
+    public void testExceptionMapper() {
+        String url = "/test/ex";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).body(equalTo("test exception mapper"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+    }
+
+    private void configureRulesFor(String resource, int count) {
+        configureRulesFor(resource, count, "default");
+    }
+
+    private void configureRulesFor(String resource, int count, String limitApp) {
+        FlowRule rule = new FlowRule()
+            .setCount(count)
+            .setGrade(RuleConstant.FLOW_GRADE_QPS);
+        rule.setResource(resource);
+        if (StringUtil.isNotBlank(limitApp)) {
+            rule.setLimitApp(limitApp);
+        }
+        FlowRuleManager.loadRules(Collections.singletonList(rule));
+    }
+}

+ 30 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/TestApplication.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author sea
+ */
+@SpringBootApplication
+public class TestApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(TestApplication.class, args);
+    }
+}

+ 92 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/jaxrs/TestResource.java

@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.jaxrs;
+
+import org.springframework.stereotype.Component;
+
+import javax.ws.rs.*;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author sea
+ */
+@Path("/test")
+@Component
+public class TestResource {
+
+    ExecutorService executor = Executors.newFixedThreadPool(5);
+
+    @Path("/hello")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String sayHello() {
+        return "Hello!";
+    }
+
+    @Path("/async-hello")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public void asyncSayHello(@Suspended final AsyncResponse asyncResponse) {
+        executor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    TimeUnit.MILLISECONDS.sleep(100);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                asyncResponse.resume("Hello!");
+            }
+        });
+    }
+
+    @Path("/hello/{name}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String sayHelloWithName(@PathParam(value = "name") String name) {
+        return "Hello " + name + " !";
+    }
+
+    @Path("/ex")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String exception() {
+        throw new RuntimeException("test exception mapper");
+    }
+
+    @Path("/400")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String badRequest() {
+        throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+                .entity("test return 400")
+                .build());
+    }
+
+    @Path("/delay/{seconds}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String delay(@PathParam(value = "seconds") long seconds) throws InterruptedException {
+        TimeUnit.SECONDS.sleep(seconds);
+        return "finish";
+    }
+}

+ 3 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/resources/application-client.yml

@@ -0,0 +1,3 @@
+resteasy:
+  jaxrs:
+    scan-packages: com.alibaba.csp.sentinel.adapter.jaxrs.exception

+ 3 - 0
sentinel-adapter/sentinel-jax-rs-adapter/src/test/resources/application-provider.yml

@@ -0,0 +1,3 @@
+resteasy:
+  jaxrs:
+    scan-packages: com.alibaba.csp.sentinel.adapter.jaxrs

+ 38 - 0
sentinel-adapter/sentinel-motan-adapter/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sentinel-adapter</artifactId>
+        <groupId>com.alibaba.csp</groupId>
+        <version>1.8.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>sentinel-motan-adapter</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <motan.version>1.1.8</motan.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.weibo</groupId>
+            <artifactId>motan-core</artifactId>
+            <version>${motan.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.weibo</groupId>
+            <artifactId>motan-transport-netty4</artifactId>
+            <version>${motan.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>

+ 89 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/MotanUtils.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan;
+
+import com.alibaba.csp.sentinel.adapter.motan.config.MotanAdapterGlobalConfig;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import com.weibo.api.motan.rpc.Caller;
+import com.weibo.api.motan.rpc.Request;
+import com.weibo.api.motan.util.ReflectUtil;
+
+/**
+ * @author zhangxn8
+ */
+public class MotanUtils {
+
+    private MotanUtils() {}
+
+    public static String getMethodResourceName(Caller<?> caller, Request request){
+        return getMethodResourceName(caller, request, false);
+    }
+
+    public static String getMethodResourceName(Caller<?> caller, Request request, Boolean useGroupAndVersion) {
+        StringBuilder buf = new StringBuilder(64);
+        String interfaceResource = useGroupAndVersion ? caller.getUrl().getPath(): caller.getInterface().getName();
+        buf.append(interfaceResource)
+                .append(":")
+                .append(request.getMethodName())
+                .append("(");
+        boolean isFirst = true;
+        try {
+            Class<?>[] classTypes = ReflectUtil.forNames(request.getParamtersDesc());
+            for (Class<?> clazz : classTypes) {
+                if (!isFirst) {
+                    buf.append(",");
+                }
+                buf.append(clazz.getName());
+                isFirst = false;
+            }
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    public static String getMethodResourceName(Caller<?> caller, Request request, String prefix) {
+        if (StringUtil.isNotBlank(prefix)) {
+            return new StringBuilder(64)
+                    .append(prefix)
+                    .append(getMethodResourceName(caller, request,MotanAdapterGlobalConfig.getMotanInterfaceGroupAndVersionEnabled()))
+                    .toString();
+        } else {
+            return getMethodResourceName(caller, request,MotanAdapterGlobalConfig.getMotanInterfaceGroupAndVersionEnabled());
+        }
+    }
+
+    public static String getInterfaceName(Caller<?> caller) {
+        return getInterfaceName(caller, false);
+    }
+
+    public static String getInterfaceName(Caller<?> caller, Boolean useGroupAndVersion) {
+        return useGroupAndVersion ? caller.getUrl().getApplication() : caller.getInterface().getName();
+    }
+
+    public static String getInterfaceName(Caller<?> caller, String prefix) {
+        if (StringUtil.isNotBlank(prefix)) {
+            return new StringBuilder(64)
+                    .append(prefix)
+                    .append(getInterfaceName(caller, MotanAdapterGlobalConfig.getMotanInterfaceGroupAndVersionEnabled()))
+                    .toString();
+        } else {
+            return getInterfaceName(caller, MotanAdapterGlobalConfig.getMotanInterfaceGroupAndVersionEnabled());
+        }
+    }
+
+}

+ 74 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/SentinelMotanConsumerFilter.java

@@ -0,0 +1,74 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.motan.config.MotanAdapterGlobalConfig;
+import com.alibaba.csp.sentinel.log.RecordLog;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.weibo.api.motan.common.MotanConstants;
+import com.weibo.api.motan.core.extension.Activation;
+import com.weibo.api.motan.core.extension.SpiMeta;
+import com.weibo.api.motan.exception.MotanAbstractException;
+import com.weibo.api.motan.filter.Filter;
+import com.weibo.api.motan.rpc.Caller;
+import com.weibo.api.motan.rpc.Request;
+import com.weibo.api.motan.rpc.Response;
+
+/**
+ * @author zhangxn8
+ */
+@Activation(key = MotanConstants.NODE_TYPE_REFERER)
+@SpiMeta(name = MotanAdapterGlobalConfig.SENTINEL_MOTAN_CONSUMER)
+public class SentinelMotanConsumerFilter implements Filter {
+
+    public SentinelMotanConsumerFilter(){
+        RecordLog.info("Sentinel motan consumer filter initialized");
+    }
+
+    @Override
+    public Response filter(Caller<?> caller, Request request) {
+        Entry interfaceEntry = null;
+        Entry methodEntry = null;
+        String prefix = MotanAdapterGlobalConfig.getMotanConsumerPrefix();
+        String interfaceResourceName = MotanUtils.getInterfaceName(caller, prefix);
+        String methodResourceName = MotanUtils.getMethodResourceName(caller, request, prefix);
+        try {
+            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
+            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT,
+                    request.getArguments());
+            Response result = caller.call(request);
+            if (result.getException() != null) {
+                Tracer.traceEntry(result.getException(), interfaceEntry);
+                Tracer.traceEntry(result.getException(), methodEntry);
+            }
+            return result;
+        } catch (BlockException e) {
+            return MotanAdapterGlobalConfig.getConsumerFallback().handle(caller, request, e);
+        } catch (MotanAbstractException e) {
+            Tracer.traceEntry(e, interfaceEntry);
+            Tracer.traceEntry(e, methodEntry);
+            throw e;
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit(1, request.getArguments());
+            }
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+        }
+    }
+}

+ 80 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/SentinelMotanProviderFilter.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.motan.config.MotanAdapterGlobalConfig;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.log.RecordLog;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.weibo.api.motan.common.MotanConstants;
+import com.weibo.api.motan.core.extension.Activation;
+import com.weibo.api.motan.core.extension.SpiMeta;
+import com.weibo.api.motan.exception.MotanAbstractException;
+import com.weibo.api.motan.filter.Filter;
+import com.weibo.api.motan.rpc.Caller;
+import com.weibo.api.motan.rpc.Request;
+import com.weibo.api.motan.rpc.Response;
+import java.util.Map;
+
+/**
+ * @author zhangxn8
+ */
+@Activation(key = MotanConstants.NODE_TYPE_SERVICE)
+@SpiMeta(name = MotanAdapterGlobalConfig.SENTINEL_MOTAN_PROVIDER)
+public class SentinelMotanProviderFilter implements Filter {
+
+    public SentinelMotanProviderFilter(){
+        RecordLog.info("Sentinel motan provider filter initialized");
+    }
+
+    @Override
+    public Response filter(Caller<?> caller, Request request) {
+        Entry interfaceEntry = null;
+        Entry methodEntry = null;
+        Map<String, String> attachment = request.getAttachments();
+        String origin = attachment.getOrDefault(MotanAdapterGlobalConfig.APPLICATION, MotanAdapterGlobalConfig.MOTAN);
+        String prefix = MotanAdapterGlobalConfig.getMotanProviderPrefix();
+        String interfaceResourceName = MotanUtils.getInterfaceName(caller, prefix);
+        String methodResourceName = MotanUtils.getMethodResourceName(caller, request, prefix);
+        try {
+            ContextUtil.enter(methodResourceName, origin);
+            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
+            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN,
+                    request.getArguments());
+            Response result = caller.call(request);
+            if (result.getException() != null) {
+                Tracer.traceEntry(result.getException(), interfaceEntry);
+                Tracer.traceEntry(result.getException(), methodEntry);
+            }
+            return result;
+        } catch (BlockException e) {
+            return MotanAdapterGlobalConfig.getProviderFallback().handle(caller, request, e);
+        } catch (MotanAbstractException e) {
+            Tracer.traceEntry(e, interfaceEntry);
+            Tracer.traceEntry(e, methodEntry);
+            throw e;
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit(1, request.getArguments());
+            }
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+            ContextUtil.exit();
+        }
+    }
+}

+ 94 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/config/MotanAdapterGlobalConfig.java

@@ -0,0 +1,94 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan.config;
+
+import com.alibaba.csp.sentinel.adapter.motan.fallback.DefaultMotanFallback;
+import com.alibaba.csp.sentinel.adapter.motan.fallback.MotanFallback;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+/**
+ * @author zhangxn8
+ */
+public class MotanAdapterGlobalConfig {
+
+    private static final String TRUE_STR = "true";
+
+    public static final String APPLICATION = "application";
+    public static final String MOTAN = "motan";
+
+    public static final String BASE_SENTINEL_MOTAN_FILTER = "baseSentinelMotanFilter";
+    public static final String MOTAN_APP_CONTEXT = "motanAppContext";
+    public static final String SENTINEL_MOTAN_CONSUMER = "sentinelMotanConsumer";
+    public static final String SENTINEL_MOTAN_PROVIDER = "sentinelMotanProvider";
+
+    public static final String MOTAN_RES_NAME_WITH_PREFIX_KEY = "csp.sentinel.motan.resource.use.prefix";
+    public static final String MOTAN_PROVIDER_RES_NAME_PREFIX_KEY = "csp.sentinel.motan.resource.provider.prefix";
+    public static final String MOTAN_CONSUMER_RES_NAME_PREFIX_KEY = "csp.sentinel.motan.resource.consumer.prefix";
+
+    public static final String MOTAN_INTERFACE_GROUP_VERSION_ENABLED = "csp.sentinel.motan.interface.group.version.enabled";
+
+    private static final String DEFAULT_MOTAN_PROVIDER_PREFIX = "motan:provider:";
+    private static final String DEFAULT_MOTAN_CONSUMER_PREFIX = "motan:consumer:";
+
+    private static volatile MotanFallback consumerFallback = new DefaultMotanFallback();
+    private static volatile MotanFallback providerFallback = new DefaultMotanFallback();
+
+    private MotanAdapterGlobalConfig() {}
+
+    public static boolean isUsePrefix() {
+        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(MOTAN_RES_NAME_WITH_PREFIX_KEY));
+    }
+
+    public static String getMotanProviderPrefix() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(MOTAN_PROVIDER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_MOTAN_PROVIDER_PREFIX;
+        }
+        return null;
+    }
+
+    public static String getMotanConsumerPrefix() {
+        if (isUsePrefix()) {
+            String config = SentinelConfig.getConfig(MOTAN_CONSUMER_RES_NAME_PREFIX_KEY);
+            return StringUtil.isNotBlank(config) ? config : DEFAULT_MOTAN_CONSUMER_PREFIX;
+        }
+        return null;
+    }
+
+    public static Boolean getMotanInterfaceGroupAndVersionEnabled() {
+        return TRUE_STR.equalsIgnoreCase(SentinelConfig.getConfig(MOTAN_INTERFACE_GROUP_VERSION_ENABLED));
+    }
+
+    public static MotanFallback getConsumerFallback() {
+        return consumerFallback;
+    }
+
+    public static void setConsumerFallback(MotanFallback consumerFallback) {
+        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
+        MotanAdapterGlobalConfig.consumerFallback = consumerFallback;
+    }
+
+    public static MotanFallback getProviderFallback() {
+        return providerFallback;
+    }
+
+    public static void setProviderFallback(MotanFallback providerFallback) {
+        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
+        MotanAdapterGlobalConfig.providerFallback = providerFallback;
+    }
+}

+ 38 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/fallback/DefaultMotanFallback.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.weibo.api.motan.rpc.Caller;
+import com.weibo.api.motan.rpc.DefaultResponse;
+import com.weibo.api.motan.rpc.Request;
+import com.weibo.api.motan.rpc.Response;
+
+/**
+ * @author zhangxn8
+ */
+public class DefaultMotanFallback implements MotanFallback{
+
+    @Override
+    public Response handle(Caller<?> caller, Request request, BlockException ex) {
+        DefaultResponse defaultResponse = new DefaultResponse();
+        defaultResponse.setException(ex.toRuntimeException());
+        defaultResponse.setRequestId(request.getRequestId());
+        defaultResponse.setAttachments(request.getAttachments());
+        defaultResponse.setRpcProtocolVersion(request.getRpcProtocolVersion());
+        return defaultResponse;
+    }
+}

+ 37 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/motan/fallback/MotanFallback.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.motan.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.weibo.api.motan.rpc.Caller;
+import com.weibo.api.motan.rpc.Request;
+import com.weibo.api.motan.rpc.Response;
+
+/**
+ * @author zhangxn8
+ */
+public interface MotanFallback {
+
+    /**
+     * Handle the block exception and provide fallback result.
+     * @param caller
+     * @param request
+     * @param ex
+     * @return
+     */
+    Response handle(Caller<?> caller, Request request, BlockException ex);
+
+}

+ 2 - 0
sentinel-adapter/sentinel-motan-adapter/src/main/resources/META-INF/services/com.weibo.api.motan.filter.Filter

@@ -0,0 +1,2 @@
+com.alibaba.csp.sentinel.adapter.motan.SentinelMotanProviderFilter
+com.alibaba.csp.sentinel.adapter.motan.SentinelMotanConsumerFilter

+ 65 - 0
sentinel-adapter/sentinel-okhttp-adapter/README.md

@@ -0,0 +1,65 @@
+# Sentinel OkHttp Adapter
+
+## Introduction
+
+Sentinel provides integration for OkHttp client to enable flow control for web requests.
+
+Add the following dependency in `pom.xml` (if you are using Maven):
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-okhttp-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+We can add the `SentinelOkHttpInterceptor` interceptor when `OkHttpClient` at initialization, for example:
+
+```java
+OkHttpClient client = new OkHttpClient.Builder()
+        .addInterceptor(new SentinelOkHttpInterceptor(new SentinelOkHttpConfig()))
+        .build();
+```
+
+## Configuration
+
+`SentinelOkHttpConfig` configuration:
+
+| name | description | type | default value |
+|------|------------|------|-------|
+| resourcePrefix | customized resource name prefix | `String` | `okhttp:` |
+| resourceExtractor | customized resource extractor | `OkHttpResourceExtractor` | `DefaultOkHttpResourceExtractor` |
+| fallback | handle request when it is blocked | `OkHttpFallback` | `DefaultOkHttpFallback` |
+
+### Resource Extractor
+
+We can define `OkHttpResourceExtractor` to customize the logic of extracting resource name from the HTTP request.
+For example: `okhttp:GET:ip:port/okhttp/back/1 ==> /okhttp/back/{id}`
+
+```java
+OkHttpResourceExtractor extractor = (request, connection) -> {
+    String resource = request.url().toString();
+    String regex = "/okhttp/back/";
+    if (resource.contains(regex)) {
+        resource = resource.substring(0, resource.indexOf(regex) + regex.length()) + "{id}";
+    }
+    return resource;
+};
+```
+
+The pattern of default resource name extractor is `${HTTP_METHOD}:${URL}` (e.g. `GET:/foo`).
+
+### Fallback (Block handling)
+
+We can define `OkHttpFallback` to handle blocked request. For example:
+
+```java
+public class DefaultOkHttpFallback implements OkHttpFallback {
+
+    @Override
+    public Response handle(Request request, Connection connection, BlockException e) {
+        return new Response(myErrorBuilder);
+    }
+}
+```

+ 68 - 0
sentinel-adapter/sentinel-okhttp-adapter/pom.xml

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sentinel-adapter</artifactId>
+        <groupId>com.alibaba.csp</groupId>
+        <version>1.8.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sentinel-okhttp-adapter</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <okhttp.version>3.6.0</okhttp.version>
+        <spring.boot.version>2.1.3.RELEASE</spring.boot.version>
+        <spring-test.version>5.1.5.RELEASE</spring-test.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>${okhttp.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+            <version>${spring.boot.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>${spring-test.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 78 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpConfig.java

@@ -0,0 +1,78 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp;
+
+import com.alibaba.csp.sentinel.adapter.okhttp.extractor.DefaultOkHttpResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.okhttp.extractor.OkHttpResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.okhttp.fallback.DefaultOkHttpFallback;
+import com.alibaba.csp.sentinel.adapter.okhttp.fallback.OkHttpFallback;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
+/**
+ * @author zhaoyuguang
+ * @author Eric Zhao
+ */
+public class SentinelOkHttpConfig {
+
+    public static final String DEFAULT_RESOURCE_PREFIX = "okhttp:";
+
+    private final String resourcePrefix;
+    private final OkHttpResourceExtractor resourceExtractor;
+    private final OkHttpFallback fallback;
+
+    public SentinelOkHttpConfig() {
+        this(DEFAULT_RESOURCE_PREFIX);
+    }
+
+    public SentinelOkHttpConfig(String resourcePrefix) {
+        this(resourcePrefix, new DefaultOkHttpResourceExtractor(), new DefaultOkHttpFallback());
+    }
+
+    public SentinelOkHttpConfig(OkHttpResourceExtractor resourceExtractor, OkHttpFallback fallback) {
+        this(DEFAULT_RESOURCE_PREFIX, resourceExtractor, fallback);
+    }
+
+    public SentinelOkHttpConfig(String resourcePrefix,
+                                OkHttpResourceExtractor resourceExtractor,
+                                OkHttpFallback fallback) {
+        AssertUtil.notNull(resourceExtractor, "resourceExtractor cannot be null");
+        AssertUtil.notNull(fallback, "fallback cannot be null");
+        this.resourcePrefix = resourcePrefix;
+        this.resourceExtractor = resourceExtractor;
+        this.fallback = fallback;
+    }
+
+    public String getResourcePrefix() {
+        return resourcePrefix;
+    }
+
+    public OkHttpResourceExtractor getResourceExtractor() {
+        return resourceExtractor;
+    }
+
+    public OkHttpFallback getFallback() {
+        return fallback;
+    }
+
+    @Override
+    public String toString() {
+        return "SentinelOkHttpConfig{" +
+            "resourcePrefix='" + resourcePrefix + '\'' +
+            ", resourceExtractor=" + resourceExtractor +
+            ", fallback=" + fallback +
+            '}';
+    }
+}

+ 67 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpInterceptor.java

@@ -0,0 +1,67 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.util.AssertUtil;
+import com.alibaba.csp.sentinel.util.StringUtil;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelOkHttpInterceptor implements Interceptor {
+
+    private final SentinelOkHttpConfig config;
+
+    public SentinelOkHttpInterceptor() {
+        this.config = new SentinelOkHttpConfig();
+    }
+
+    public SentinelOkHttpInterceptor(SentinelOkHttpConfig config) {
+        AssertUtil.notNull(config, "config cannot be null");
+        this.config = config;
+    }
+
+    @Override
+    public Response intercept(Chain chain) throws IOException {
+        Entry entry = null;
+        try {
+            Request request = chain.request();
+            String name = config.getResourceExtractor().extract(request, chain.connection());
+            if (StringUtil.isNotBlank(config.getResourcePrefix())) {
+                name = config.getResourcePrefix() + name;
+            }
+            entry = SphU.entry(name, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+            return chain.proceed(request);
+        } catch (BlockException e) {
+            return config.getFallback().handle(chain.request(), chain.connection(), e);
+        } catch (IOException ex) {
+            Tracer.traceEntry(ex, entry);
+            throw ex;
+        } finally {
+            if (entry != null) {
+                entry.exit();
+            }
+        }
+    }
+}

+ 30 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/DefaultOkHttpResourceExtractor.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.extractor;
+
+import okhttp3.Connection;
+import okhttp3.Request;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultOkHttpResourceExtractor implements OkHttpResourceExtractor {
+
+    @Override
+    public String extract(Request request, Connection connection) {
+        return request.method() + ":" + request.url().toString();
+    }
+}

+ 34 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/OkHttpResourceExtractor.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.extractor;
+
+import okhttp3.Connection;
+import okhttp3.Request;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface OkHttpResourceExtractor {
+
+    /**
+     * Extracts the resource name from the HTTP request.
+     *
+     * @param request    HTTP request entity
+     * @param connection HTTP connection
+     * @return the resource name of current request
+     */
+    String extract(Request request, Connection connection);
+}

+ 34 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/DefaultOkHttpFallback.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import okhttp3.Connection;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * @author zhaoyuguang
+ */
+public class DefaultOkHttpFallback implements OkHttpFallback {
+
+    @Override
+    public Response handle(Request request, Connection connection, BlockException e) {
+        // Just wrap and throw the exception.
+        throw new SentinelRpcException(e);
+    }
+}

+ 29 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/OkHttpFallback.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import okhttp3.Connection;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * @author zhaoyuguang
+ */
+public interface OkHttpFallback {
+
+    Response handle(Request request, Connection connection, BlockException e);
+}

+ 98 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/SentinelOkHttpInterceptorTest.java

@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.okhttp.app.TestApplication;
+import com.alibaba.csp.sentinel.adapter.okhttp.extractor.OkHttpResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.okhttp.fallback.DefaultOkHttpFallback;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import okhttp3.Connection;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author zhaoyuguang
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class,
+        webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+        properties = {
+                "server.port=8086"
+        })
+public class SentinelOkHttpInterceptorTest {
+
+    @Value("${server.port}")
+    private Integer port;
+
+    @Test
+    public void testSentinelOkHttpInterceptor0() throws Exception {
+        // With prefix
+        SentinelOkHttpConfig config = new SentinelOkHttpConfig("okhttp:");
+        String url0 = "http://localhost:" + port + "/okhttp/back";
+        OkHttpClient client = new OkHttpClient.Builder()
+                .addInterceptor(new SentinelOkHttpInterceptor(config))
+                .build();
+        Request request = new Request.Builder()
+                .url(url0)
+                .build();
+        System.out.println(client.newCall(request).execute().body().string());
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(config.getResourcePrefix() + "GET:" + url0);
+        assertNotNull(cn);
+
+        Constants.ROOT.removeChildList();
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+    }
+
+    @Test
+    public void testSentinelOkHttpInterceptor1() throws Exception {
+
+        String url0 = "http://localhost:" + port + "/okhttp/back/1";
+        SentinelOkHttpConfig config = new SentinelOkHttpConfig(new OkHttpResourceExtractor() {
+            @Override
+            public String extract(Request request, Connection connection) {
+                String regex = "/okhttp/back/";
+                String url = request.url().toString();
+                if (url.contains(regex)) {
+                    url = url.substring(0, url.indexOf(regex) + regex.length()) + "{id}";
+                }
+                return request.method() + ":" + url;
+            }
+        }, new DefaultOkHttpFallback());
+        OkHttpClient client = new OkHttpClient.Builder()
+                .addInterceptor(new SentinelOkHttpInterceptor(config))
+                .build();
+        Request request = new Request.Builder()
+                .url(url0)
+                .build();
+        System.out.println(client.newCall(request).execute().body().string());
+
+        String url1 = config.getResourcePrefix() + "GET:http://localhost:" + port + "/okhttp/back/{id}";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(url1);
+        assertNotNull(cn);
+
+        Constants.ROOT.removeChildList();
+        ClusterBuilderSlot.getClusterNodeMap().clear();
+    }
+}

+ 30 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/app/TestApplication.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author zhaoyuguang
+ */
+@SpringBootApplication
+public class TestApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(TestApplication.class);
+    }
+}

+ 37 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/app/controller/TestController.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.app.controller;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author zhaoyuguang
+ */
+@RestController
+public class TestController {
+
+    @RequestMapping("/okhttp/back")
+    public String back() {
+        return "Welcome Back!";
+    }
+
+    @RequestMapping("/okhttp/back/{id}")
+    public String back(@PathVariable String id) {
+        return "Welcome Back! " + id;
+    }
+}

+ 38 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/config/SentinelOkHttpConfigTest.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.config;
+
+import com.alibaba.csp.sentinel.adapter.okhttp.SentinelOkHttpConfig;
+import com.alibaba.csp.sentinel.adapter.okhttp.extractor.DefaultOkHttpResourceExtractor;
+import com.alibaba.csp.sentinel.adapter.okhttp.fallback.DefaultOkHttpFallback;
+
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class SentinelOkHttpConfigTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigSetCleaner() {
+        SentinelOkHttpConfig config = new SentinelOkHttpConfig(null, new DefaultOkHttpFallback());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConfigSetFallback() {
+        SentinelOkHttpConfig config = new SentinelOkHttpConfig(new DefaultOkHttpResourceExtractor(), null);
+    }
+}

+ 59 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/extractor/OkHttpResourceExtractorTest.java

@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.extractor;
+
+import okhttp3.Connection;
+import okhttp3.Request;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author zhaoyuguang
+ */
+public class OkHttpResourceExtractorTest {
+
+    @Test
+    public void testDefaultOkHttpResourceExtractor() {
+        OkHttpResourceExtractor extractor = new DefaultOkHttpResourceExtractor();
+        String url = "http://localhost:8083/okhttp/back";
+        Request request = new Request.Builder()
+            .url(url)
+            .build();
+        String resource = extractor.extract(request, null);
+        assertEquals("GET:" + url, resource);
+    }
+
+    @Test
+    public void testCustomizeOkHttpUrlCleaner() {
+        OkHttpResourceExtractor extractor = new OkHttpResourceExtractor() {
+            @Override
+            public String extract(Request request, Connection connection) {
+                String regex = "/okhttp/back/";
+                String url = request.url().toString();
+                if (url.contains(regex)) {
+                    url = url.substring(0, url.indexOf(regex) + regex.length()) + "{id}";
+                }
+                return request.method() + ":" + url;
+            }
+        };
+        String url = "http://localhost:8083/okhttp/back/abc";
+        Request request = new Request.Builder()
+            .url(url)
+            .build();
+        assertEquals("GET:http://localhost:8083/okhttp/back/{id}", extractor.extract(request, null));
+    }
+}

+ 34 - 0
sentinel-adapter/sentinel-okhttp-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/okhttp/fallback/OkHttpFallbackTest.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.okhttp.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
+import org.junit.Test;
+
+/**
+ * @author zhaoyuguang
+ */
+public class OkHttpFallbackTest {
+
+    @Test(expected = SentinelRpcException.class)
+    public void testDefaultOkHttpFallback() {
+        BlockException e = new FlowException("xxx");
+        OkHttpFallback fallback = new DefaultOkHttpFallback();
+        fallback.handle(null, null, e);
+    }
+}

+ 72 - 0
sentinel-adapter/sentinel-quarkus-adapter/README.md

@@ -0,0 +1,72 @@
+# Sentinel Quarkus Adapter
+
+Sentinel provides `sentinel-annotation-quarkus-adapter` and `sentinel-jax-rs-quarkus-adapter` to
+adapt [sentinel-annotation-cdi-interceptor](https://github.com/alibaba/Sentinel/tree/master/sentinel-extension/sentiel-annotation-cdi-interceptor)
+and [sentinel-jax-rs-adapter](https://github.com/alibaba/Sentinel/tree/master/sentinel-adapter/sentinel-jax-rs-adapter) for Quarkus.
+
+The integration module also provides `sentinel-native-image-quarkus-adapter` to support running Sentinel with Quarkus in native image mode.
+
+To use sentinel-jax-rs-quarkus-adapter, you can simply add the following dependency to your `pom.xml`:
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-jax-rs-quarkus-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+To use sentinel-annotation-quarkus-adapter, you can simply add the following dependency to your `pom.xml`:
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-annotation-quarkus-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+When Quarkus application started, you can see the enabled feature like:
+
+```
+INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy, sentinel-annotation, sentinel-jax-rs]
+```
+
+## For Quarkus native image
+
+If you want to integrate Quarkus with Sentinel while running in native image mode,
+you should add the following dependency to your `pom.xml`:
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-native-image-quarkus-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+And then add `--allow-incomplete-classpath` to `quarkus.native.additional-build-args`.
+
+If you're using `sentinel-jax-rs-quarkus-adapter`, you'll need to set `quarkus.native.auto-service-loader-registration` to true.
+
+When Quarkus application started, you can see the enabled feature like:
+
+```
+INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, sentinel-annotation, sentinel-jax-rs, sentinel-native-image]
+```
+
+For more details you may refer to the `pom.xml` of [sentinel-demo-quarkus](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-quarkus).
+
+### Limitations
+
+`sentinel-native-image-quarkus-adapter` currently relies on `sentinel-logging-slf4j` to help Sentinel
+run in native image mode easily, because `quarkus-core` provides `Target_org_slf4j_LoggerFactory` to substitute `getLogger` method.
+
+Currently `sentinel-transport-simple-http` can work in native image mode, while `sentinel-transport-netty-http` cannot work in native image mode without extra config or substitutions.
+
+## References for build native image or AOT
+
+- [Quarkus - Tips for writing native applications](https://quarkus.io/guides/writing-native-applications-tips)
+- [Quarkus - Class Loading Reference](https://quarkus.io/guides/class-loading-reference)
+- [SubstrateVM LIMITATIONS](https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md)
+- [Accessing resources in Substrate VM images](https://github.com/oracle/graal/blob/master/substratevm/RESOURCES.md)

+ 55 - 0
sentinel-adapter/sentinel-quarkus-adapter/pom.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-adapter</artifactId>
+        <version>1.8.3</version>
+    </parent>
+
+    <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.parameters>true</maven.compiler.parameters>
+        <quarkus.version>1.4.1.Final</quarkus.version>
+        <compiler-plugin.version>3.8.1</compiler-plugin.version>
+    </properties>
+
+    <modules>
+        <module>sentinel-annotation-quarkus-adapter-deployment</module>
+        <module>sentinel-annotation-quarkus-adapter-runtime</module>
+        <module>sentinel-jax-rs-quarkus-adapter-deployment</module>
+        <module>sentinel-jax-rs-quarkus-adapter-runtime</module>
+        <module>sentinel-native-image-quarkus-adapter-deployment</module>
+        <module>sentinel-native-image-quarkus-adapter-runtime</module>
+    </modules>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-bom-deployment</artifactId>
+                <version>${quarkus.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>${compiler-plugin.version}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>

+ 72 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/pom.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-annotation-quarkus-adapter-deployment</artifactId>
+    <name>sentinel-annotation-quarkus-adapter-deployment</name>
+
+    <properties>
+        <java.source.version>1.8</java.source.version>
+        <java.target.version>1.8</java.target.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-arc-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-annotation-quarkus-adapter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit5-internal</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-arc-deployment</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 46 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/SentinelAnnotationQuarkusAdapterProcessor.java

@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.annotation.deployment;
+
+import com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceInterceptor;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author sea
+ */
+class SentinelAnnotationQuarkusAdapterProcessor {
+
+    private static final String FEATURE_ANNOTATION = "sentinel-annotation";
+
+    @BuildStep
+    void feature(BuildProducer<FeatureBuildItem> featureProducer) {
+        featureProducer.produce(new FeatureBuildItem(FEATURE_ANNOTATION));
+    }
+
+    @BuildStep
+    List<AdditionalBeanBuildItem> additionalBeans() {
+        return Arrays.asList(
+                new AdditionalBeanBuildItem(SentinelResourceInterceptor.class)
+        );
+    }
+
+}

+ 84 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/FooService.java

@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.quarkus.annotation.deployment;
+import com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceBinding;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+
+import javax.enterprise.context.ApplicationScoped;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * @author Eric Zhao
+ * @author sea
+ */
+@ApplicationScoped
+public class FooService {
+
+    @SentinelResourceBinding(value = "apiFoo", blockHandler = "fooBlockHandler",
+        exceptionsToTrace = {IllegalArgumentException.class})
+    public String foo(int i) throws Exception {
+        if (i == 5758) {
+            throw new IllegalAccessException();
+        }
+        if (i == 5763) {
+            throw new IllegalArgumentException();
+        }
+        return "Hello for " + i;
+    }
+
+    @SentinelResourceBinding(value = "apiFooWithFallback", blockHandler = "fooBlockHandler", fallback = "fooFallbackFunc",
+        exceptionsToTrace = {IllegalArgumentException.class})
+    public String fooWithFallback(int i) throws Exception {
+        if (i == 5758) {
+            throw new IllegalAccessException();
+        }
+        if (i == 5763) {
+            throw new IllegalArgumentException();
+        }
+        return "Hello for " + i;
+    }
+
+    @SentinelResourceBinding(value = "apiAnotherFooWithDefaultFallback", defaultFallback = "globalDefaultFallback",
+        fallbackClass = {FooUtil.class})
+    public String anotherFoo(int i) {
+        if (i == 5758) {
+            throw new IllegalArgumentException("oops");
+        }
+        return "Hello for " + i;
+    }
+
+    @SentinelResourceBinding(blockHandler = "globalBlockHandler", blockHandlerClass = FooUtil.class)
+    public int random() {
+        return ThreadLocalRandom.current().nextInt(0, 30000);
+    }
+
+    @SentinelResourceBinding(value = "apiBaz", blockHandler = "bazBlockHandler",
+            exceptionsToIgnore = {IllegalMonitorStateException.class})
+    public String baz(String name) {
+        if (name.equals("fail")) {
+            throw new IllegalMonitorStateException("boom!");
+        }
+        return "cheers, " + name;
+    }
+
+    public String fooBlockHandler(int i, BlockException ex) {
+        return "Oops, " + i;
+    }
+
+    public String fooFallbackFunc(int i) {
+        return "eee...";
+    }
+}

+ 37 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/FooUtil.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.quarkus.annotation.deployment;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+
+/**
+ * @author Eric Zhao
+ */
+public class FooUtil {
+
+    public static final int BLOCK_FLAG = 88888;
+    public static final String FALLBACK_DEFAULT_RESULT = "fallback";
+
+    public static int globalBlockHandler(BlockException ex) {
+        System.out.println("Oops: " + ex.getClass().getSimpleName());
+        return BLOCK_FLAG;
+    }
+
+    public static String globalDefaultFallback(Throwable t) {
+        System.out.println("Fallback caught: " + t.getClass().getSimpleName());
+        return FALLBACK_DEFAULT_RESULT;
+    }
+}

+ 195 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/annotation/deployment/SentinelAnnotationQuarkusAdapterTest.java

@@ -0,0 +1,195 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.annotation.deployment;
+
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import com.alibaba.csp.sentinel.util.MethodUtil;
+import io.quarkus.arc.ArcUndeclaredThrowableException;
+import io.quarkus.test.QuarkusUnitTest;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+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 org.junit.jupiter.api.extension.RegisterExtension;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * @author sea
+ */
+public class SentinelAnnotationQuarkusAdapterTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap
+                    .create(JavaArchive.class)
+                    .addClasses(FooService.class, FooUtil.class)
+                    .addPackage("com.alibaba.csp.sentinel.annotation.cdi.interceptor")
+            );
+
+    @Inject
+    FooService fooService;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        FlowRuleManager.loadRules(new ArrayList<FlowRule>());
+        ClusterBuilderSlot.resetClusterNodes();
+    }
+
+    @AfterEach
+    public void tearDown() throws Exception {
+        FlowRuleManager.loadRules(new ArrayList<FlowRule>());
+        ClusterBuilderSlot.resetClusterNodes();
+    }
+
+    @Test
+    public void testForeignBlockHandlerClass() throws Exception {
+        assertThat(fooService.random()).isNotEqualTo(FooUtil.BLOCK_FLAG);
+        String resourceName = MethodUtil.resolveMethodName(FooService.class.getDeclaredMethod("random"));
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+
+        FlowRuleManager.loadRules(Collections.singletonList(
+                new FlowRule(resourceName).setCount(0)
+        ));
+        assertThat(fooService.random()).isEqualTo(FooUtil.BLOCK_FLAG);
+        assertThat(cn.blockQps()).isPositive();
+    }
+
+    @Test
+    public void testBlockHandlerNotFound() {
+        assertThat(fooService.baz("Sentinel")).isEqualTo("cheers, Sentinel");
+        String resourceName = "apiBaz";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+
+        FlowRuleManager.loadRules(Collections.singletonList(
+                new FlowRule(resourceName).setCount(0)
+        ));
+
+        assertThrows(ArcUndeclaredThrowableException.class, () -> {
+            fooService.baz("Sentinel");
+        });
+    }
+
+    @Test
+    public void testAnnotationExceptionsToIgnore() {
+        assertThat(fooService.baz("Sentinel")).isEqualTo("cheers, Sentinel");
+        String resourceName = "apiBaz";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+        assertThrows(IllegalMonitorStateException.class, () -> {
+            fooService.baz("fail");
+        });
+        assertThat(cn.exceptionQps()).isZero();
+    }
+
+    @Test
+    public void testFallbackWithNoParams() throws Exception {
+        assertThat(fooService.fooWithFallback(1)).isEqualTo("Hello for 1");
+        String resourceName = "apiFooWithFallback";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+
+        // Fallback should be ignored for this.
+        try {
+            fooService.fooWithFallback(5758);
+            fail("should not reach here");
+        } catch (IllegalAccessException e) {
+            assertThat(cn.exceptionQps()).isZero();
+        }
+
+        // Fallback should take effect.
+        assertThat(fooService.fooWithFallback(5763)).isEqualTo("eee...");
+        assertThat(cn.exceptionQps()).isPositive();
+        assertThat(cn.blockQps()).isZero();
+
+        FlowRuleManager.loadRules(Collections.singletonList(
+                new FlowRule(resourceName).setCount(0)
+        ));
+        // Fallback should not take effect for BlockException, as blockHandler is configured.
+        assertThat(fooService.fooWithFallback(2221)).isEqualTo("Oops, 2221");
+        assertThat(cn.blockQps()).isPositive();
+    }
+
+    @Test
+    public void testDefaultFallbackWithSingleParam() {
+        assertThat(fooService.anotherFoo(1)).isEqualTo("Hello for 1");
+        String resourceName = "apiAnotherFooWithDefaultFallback";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+
+        // Default fallback should take effect.
+        assertThat(fooService.anotherFoo(5758)).isEqualTo(FooUtil.FALLBACK_DEFAULT_RESULT);
+        assertThat(cn.exceptionQps()).isPositive();
+        assertThat(cn.blockQps()).isZero();
+
+        FlowRuleManager.loadRules(Collections.singletonList(
+                new FlowRule(resourceName).setCount(0)
+        ));
+        // Default fallback should also take effect for BlockException.
+        assertThat(fooService.anotherFoo(5758)).isEqualTo(FooUtil.FALLBACK_DEFAULT_RESULT);
+        assertThat(cn.blockQps()).isPositive();
+    }
+
+    @Test
+    public void testNormalBlockHandlerAndFallback() throws Exception {
+        assertThat(fooService.foo(1)).isEqualTo("Hello for 1");
+        String resourceName = "apiFoo";
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertThat(cn).isNotNull();
+        assertThat(cn.passQps()).isPositive();
+
+        // Test for biz exception.
+        try {
+            fooService.foo(5758);
+            fail("should not reach here");
+        } catch (Exception ex) {
+            // Should not be traced.
+            assertThat(cn.exceptionQps()).isZero();
+        }
+
+        try {
+            fooService.foo(5763);
+            fail("should not reach here");
+        } catch (Exception ex) {
+            assertThat(cn.exceptionQps()).isPositive();
+        }
+
+        // Test for blockHandler
+        FlowRuleManager.loadRules(Collections.singletonList(
+                new FlowRule(resourceName).setCount(0)
+        ));
+        assertThat(fooService.foo(1121)).isEqualTo("Oops, 1121");
+        assertThat(cn.blockQps()).isPositive();
+    }
+}

+ 63 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-runtime/pom.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-annotation-quarkus-adapter</artifactId>
+    <name>sentinel-annotation-quarkus-adapter</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core</artifactId>
+            <version>${quarkus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-annotation-cdi-interceptor</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-bootstrap-maven-plugin</artifactId>
+                <version>${quarkus.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>extension-descriptor</goal>
+                        </goals>
+                        <phase>compile</phase>
+                        <configuration>
+                            <deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
+                            </deployment>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 13 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-annotation-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml

@@ -0,0 +1,13 @@
+---
+name: "Sentinel annotation CDI extension"
+metadata:
+  keywords:
+    - "sentinel"
+    - "rate-limiting"
+    - "resiliency"
+    - "circuit-breaker"
+    - "fault-tolerance"
+  categories:
+    - "fault-tolerance"
+    - "cloud"
+  status: "preview"

+ 77 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/pom.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-jax-rs-quarkus-adapter-deployment</artifactId>
+    <name>sentinel-jax-rs-quarkus-adapter-deployment</name>
+
+    <properties>
+        <java.source.version>1.8</java.source.version>
+        <java.target.version>1.8</java.target.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-arc-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy-server-common-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-jax-rs-quarkus-adapter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit5-internal</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-resteasy-deployment</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 37 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/SentinelJaxRsQuarkusAdapterProcessor.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.jaxrs.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import org.jboss.logging.Logger;
+
+/**
+ * @author sea
+ */
+class SentinelJaxRsQuarkusAdapterProcessor {
+
+    private static final Logger logger = Logger.getLogger(SentinelJaxRsQuarkusAdapterProcessor.class);
+
+    private static final String FEATURE_JAX_RS = "sentinel-jax-rs";
+
+    @BuildStep
+    void feature(BuildProducer<FeatureBuildItem> featureProducer) {
+        featureProducer.produce(new FeatureBuildItem(FEATURE_JAX_RS));
+    }
+
+}

+ 242 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/SentinelJaxRsQuarkusAdapterTest.java

@@ -0,0 +1,242 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.jaxrs.deployment;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig;
+import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.SentinelJaxRsFallback;
+import com.alibaba.csp.sentinel.adapter.jaxrs.request.RequestOriginParser;
+import com.alibaba.csp.sentinel.node.ClusterNode;
+import com.alibaba.csp.sentinel.node.EntranceNode;
+import com.alibaba.csp.sentinel.node.Node;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
+import com.alibaba.csp.sentinel.util.StringUtil;
+import io.quarkus.test.QuarkusUnitTest;
+import io.restassured.response.Response;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.MediaType;
+import java.util.Collections;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @author sea
+ */
+public class SentinelJaxRsQuarkusAdapterTest {
+
+    private static final String HELLO_STR = "Hello!";
+
+    @RegisterExtension
+    static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+            .setArchiveProducer(() -> ShrinkWrap
+            .create(JavaArchive.class)
+                    .addClasses(TestResource.class));
+
+    @AfterEach
+    public void cleanUp() {
+        FlowRuleManager.loadRules(null);
+        ClusterBuilderSlot.resetClusterNodes();
+    }
+
+    @Test
+    public void testGetHello() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+
+        String context = "";
+        for (Node n : Constants.ROOT.getChildList()) {
+            if (n instanceof EntranceNode) {
+                String id = ((EntranceNode) n).getId().getName();
+                if (url.equals(id)) {
+                    context = ((EntranceNode) n).getId().getName();
+                }
+            }
+        }
+        assertEquals("", context);
+    }
+
+    @Test
+    public void testAsyncGetHello() {
+        String url = "/test/async-hello";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+
+        String context = "";
+        for (Node n : Constants.ROOT.getChildList()) {
+            if (n instanceof EntranceNode) {
+                String id = ((EntranceNode) n).getId().getName();
+                if (url.equals(id)) {
+                    context = ((EntranceNode) n).getId().getName();
+                }
+            }
+        }
+        assertEquals("", context);
+    }
+
+    @Test
+    public void testUrlPathParam() {
+        String url = "/test/hello/{name}";
+        String resourceName = "GET:" + url;
+
+        String url1 = "/test/hello/abc";
+        Response response1 = given().get(url1);
+        response1.then().statusCode(200).body(equalTo("Hello abc !"));
+
+        String url2 = "/test/hello/def";
+        Response response2 = given().get(url2);
+        response2.then().statusCode(200).body(equalTo("Hello def !"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(2, cn.passQps(), 0.01);
+
+        assertNull(ClusterBuilderSlot.getClusterNode("GET:" + url1));
+        assertNull(ClusterBuilderSlot.getClusterNode("GET:" + url2));
+    }
+
+    @Test
+    public void testDefaultFallback() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        configureRulesFor(resourceName, 0);
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.TOO_MANY_REQUESTS.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCustomFallback() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+        SentinelJaxRsConfig.setJaxRsFallback(new SentinelJaxRsFallback() {
+            @Override
+            public javax.ws.rs.core.Response fallbackResponse(String route, Throwable cause) {
+                return javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.OK)
+                        .entity("Blocked by Sentinel (flow limiting)")
+                        .type(MediaType.APPLICATION_JSON_TYPE)
+                        .build();
+            }
+
+            @Override
+            public Future<javax.ws.rs.core.Response> fallbackFutureResponse(final String route, final Throwable cause) {
+                return new FutureTask<>(new Callable<javax.ws.rs.core.Response>() {
+                    @Override
+                    public javax.ws.rs.core.Response call() throws Exception {
+                        return fallbackResponse(route, cause);
+                    }
+                });
+            }
+        });
+
+
+        configureRulesFor(resourceName, 0);
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.OK.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(0, cn.passQps(), 0.01);
+    }
+
+    @Test
+    public void testCustomRequestOriginParser() {
+        String url = "/test/hello";
+        String resourceName = "GET:" + url;
+
+        String limitOrigin = "appB";
+        final String headerName = "X-APP";
+        configureRulesFor(resourceName, 0, limitOrigin);
+
+        SentinelJaxRsConfig.setRequestOriginParser(new RequestOriginParser() {
+            @Override
+            public String parseOrigin(ContainerRequestContext request) {
+                String origin = request.getHeaderString(headerName);
+                return origin != null ? origin : "";
+            }
+        });
+
+        Response response = given()
+                .header(headerName, "appA").get(url);
+        response.then().statusCode(200).body(equalTo(HELLO_STR));
+
+        Response blockedResp = given()
+                .header(headerName, "appB")
+                .get(url);
+        blockedResp.then().statusCode(javax.ws.rs.core.Response.Status.TOO_MANY_REQUESTS.getStatusCode())
+                .body(equalTo("Blocked by Sentinel (flow limiting)"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+        assertEquals(1, cn.passQps(), 0.01);
+        assertEquals(1, cn.blockQps(), 0.01);
+    }
+
+    @Test
+    public void testExceptionMapper() {
+        String url = "/test/ex";
+        String resourceName = "GET:" + url;
+        Response response = given().get(url);
+        response.then().statusCode(javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).body(equalTo("test exception mapper"));
+
+        ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName);
+        assertNotNull(cn);
+    }
+
+    private void configureRulesFor(String resource, int count) {
+        configureRulesFor(resource, count, "default");
+    }
+
+    private void configureRulesFor(String resource, int count, String limitApp) {
+        FlowRule rule = new FlowRule()
+                .setCount(count)
+                .setGrade(RuleConstant.FLOW_GRADE_QPS);
+        rule.setResource(resource);
+        if (StringUtil.isNotBlank(limitApp)) {
+            rule.setLimitApp(limitApp);
+        }
+        FlowRuleManager.loadRules(Collections.singletonList(rule));
+    }
+}

+ 90 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-deployment/src/test/java/com/alibaba/csp/sentinel/adapter/quarkus/jaxrs/deployment/TestResource.java

@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.jaxrs.deployment;
+
+
+import javax.ws.rs.*;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author sea
+ */
+@Path("/test")
+public class TestResource {
+
+    ExecutorService executor = Executors.newFixedThreadPool(5);
+
+    @Path("/hello")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String sayHello() {
+        return "Hello!";
+    }
+
+    @Path("/async-hello")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public void asyncSayHello(@Suspended final AsyncResponse asyncResponse) {
+        executor.submit(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    TimeUnit.MILLISECONDS.sleep(100);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                asyncResponse.resume("Hello!");
+            }
+        });
+    }
+
+    @Path("/hello/{name}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String sayHelloWithName(@PathParam(value = "name") String name) {
+        return "Hello " + name + " !";
+    }
+
+    @Path("/ex")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String exception() {
+        throw new RuntimeException("test exception mapper");
+    }
+
+    @Path("/400")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String badRequest() {
+        throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST)
+                .entity("test return 400")
+                .build());
+    }
+
+    @Path("/delay/{seconds}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String delay(@PathParam(value = "seconds") long seconds) throws InterruptedException {
+        TimeUnit.SECONDS.sleep(seconds);
+        return "finish";
+    }
+}

+ 63 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/pom.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-jax-rs-quarkus-adapter</artifactId>
+    <name>sentinel-jax-rs-quarkus-adapter</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core</artifactId>
+            <version>${quarkus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-jax-rs-adapter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-bootstrap-maven-plugin</artifactId>
+                <version>${quarkus.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>extension-descriptor</goal>
+                        </goals>
+                        <phase>compile</phase>
+                        <configuration>
+                            <deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
+                            </deployment>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 14 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml

@@ -0,0 +1,14 @@
+---
+name: "Sentinel extension for JAX-RS"
+metadata:
+  keywords:
+    - "sentinel"
+    - "rate-limiting"
+    - "resiliency"
+    - "circuit-breaker"
+    - "fault-tolerance"
+    - "jax-rs"
+  categories:
+    - "fault-tolerance"
+    - "cloud"
+  status: "preview"

+ 2 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-jax-rs-quarkus-adapter-runtime/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers

@@ -0,0 +1,2 @@
+com.alibaba.csp.sentinel.adapter.jaxrs.SentinelJaxRsProviderFilter
+com.alibaba.csp.sentinel.adapter.jaxrs.exception.DefaultExceptionMapper

+ 60 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-deployment/pom.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-native-image-quarkus-adapter-deployment</artifactId>
+    <name>sentinel-native-image-quarkus-adapter-deployment</name>
+
+    <properties>
+        <java.source.version>1.8</java.source.version>
+        <java.target.version>1.8</java.target.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-arc-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.graalvm.nativeimage</groupId>
+            <artifactId>svm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-native-image-quarkus-adapter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 73 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-deployment/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/nativeimage/SentinelNativeImageProcessor.java

@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.nativeimage;
+
+import com.alibaba.csp.sentinel.slots.DefaultSlotChainBuilder;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
+import io.quarkus.deployment.pkg.steps.NativeBuild;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author sea
+ */
+class SentinelNativeImageProcessor {
+
+    private static final String FEATURE_NATIVE_IMAGE = "sentinel-native-image";
+
+    @BuildStep
+    void feature(BuildProducer<FeatureBuildItem> featureProducer) {
+        featureProducer.produce(new FeatureBuildItem(FEATURE_NATIVE_IMAGE));
+    }
+
+    @BuildStep(onlyIf = NativeBuild.class)
+    List<RuntimeInitializedClassBuildItem> runtimeInitializedClasses() {
+        return Arrays.asList(
+                new RuntimeInitializedClassBuildItem("com.alibaba.fastjson.serializer.JodaCodec"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.fastjson.serializer.GuavaCodec"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.fastjson.support.moneta.MonetaCodec"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.Env"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.init.InitExecutor"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.cluster.ClusterStateManager"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.node.metric.MetricTimerListener"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.node.metric.MetricWriter"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.util.TimeUtil"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.eagleeye.StatLogController"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.slots.logger.EagleEyeLogUtil"),
+                new RuntimeInitializedClassBuildItem("com.alibaba.csp.sentinel.eagleeye.EagleEye"));
+    }
+
+    @BuildStep(onlyIf = NativeBuild.class)
+    ReflectiveClassBuildItem setupSentinelReflectiveClasses() {
+        return new ReflectiveClassBuildItem(true, true, true,
+                DefaultSlotChainBuilder.class.getName());
+    }
+
+    @BuildStep(onlyIf = NativeBuild.class)
+    @Record(ExecutionTime.STATIC_INIT)
+    void record(SentinelRecorder recorder) {
+        recorder.init();
+    }
+}

+ 75 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/pom.xml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.alibaba.csp</groupId>
+        <artifactId>sentinel-quarkus-adapter-parent</artifactId>
+        <version>1.8.3</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>sentinel-native-image-quarkus-adapter</artifactId>
+    <name>sentinel-native-image-quarkus-adapter</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core</artifactId>
+            <version>${quarkus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.graalvm.nativeimage</groupId>
+            <artifactId>svm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-transport-simple-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-parameter-flow-control</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-logging-slf4j</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-bootstrap-maven-plugin</artifactId>
+                <version>${quarkus.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>extension-descriptor</goal>
+                        </goals>
+                        <phase>compile</phase>
+                        <configuration>
+                            <deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
+                            </deployment>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>io.quarkus</groupId>
+                            <artifactId>quarkus-extension-processor</artifactId>
+                            <version>${quarkus.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 52 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/src/main/java/com/alibaba/csp/sentinel/adapter/quarkus/nativeimage/SentinelRecorder.java

@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.quarkus.nativeimage;
+
+import com.alibaba.csp.sentinel.command.vo.NodeVo;
+import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
+import com.alibaba.csp.sentinel.slots.system.SystemRule;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.alibaba.fastjson.serializer.SerializeConfig;
+import io.quarkus.runtime.annotations.Recorder;
+
+/**
+ * @author sea
+ */
+@Recorder
+public class SentinelRecorder {
+
+    /**
+     * register fastjson serializer deserializer class info
+     */
+    public void init() {
+        SerializeConfig.getGlobalInstance().getObjectWriter(NodeVo.class);
+        SerializeConfig.getGlobalInstance().getObjectWriter(FlowRule.class);
+        SerializeConfig.getGlobalInstance().getObjectWriter(SystemRule.class);
+        SerializeConfig.getGlobalInstance().getObjectWriter(DegradeRule.class);
+        SerializeConfig.getGlobalInstance().getObjectWriter(AuthorityRule.class);
+        SerializeConfig.getGlobalInstance().getObjectWriter(ParamFlowRule.class);
+
+        ParserConfig.getGlobalInstance().getDeserializer(NodeVo.class);
+        ParserConfig.getGlobalInstance().getDeserializer(FlowRule.class);
+        ParserConfig.getGlobalInstance().getDeserializer(SystemRule.class);
+        ParserConfig.getGlobalInstance().getDeserializer(DegradeRule.class);
+        ParserConfig.getGlobalInstance().getDeserializer(AuthorityRule.class);
+        ParserConfig.getGlobalInstance().getDeserializer(ParamFlowRule.class);
+    }
+}

+ 13 - 0
sentinel-adapter/sentinel-quarkus-adapter/sentinel-native-image-quarkus-adapter-runtime/src/main/resources/META-INF/quarkus-extension.yaml

@@ -0,0 +1,13 @@
+---
+name: "Sentinel native image extension"
+metadata:
+  keywords:
+    - "sentinel"
+    - "rate-limiting"
+    - "circuit-breaker"
+    - "native-image"
+    - "fault-tolerance"
+  categories:
+    - "cloud"
+    - "fault-tolerance"
+  status: "preview"

+ 64 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/README.md

@@ -0,0 +1,64 @@
+# Sentinel SOFARPC Adapter
+
+Sentinel SOFARPC Adapter provides service provider filter and consumer filter
+for [SOFARPC](https://www.sofastack.tech/projects/sofa-rpc) services.
+
+**Note: This adapter supports SOFARPC 5.4.x version and above, and 5.6.x is officially recommended.**
+
+To use Sentinel SOFARPC Adapter, you can simply add the following dependency to your `pom.xml`:
+
+```xml
+<dependency>
+    <groupId>com.alibaba.csp</groupId>
+    <artifactId>sentinel-sofa-rpc-adapter</artifactId>
+    <version>x.y.z</version>
+</dependency>
+```
+
+The Sentinel filters are **enabled by default**. Once you add the dependency,
+the SOFARPC services and methods will become protected resources in Sentinel,
+which can leverage Sentinel's flow control and guard ability when rules are configured.
+Demos can be found in [sentinel-demo-sofa-rpc](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-sofa-rpc).
+
+If you don't want the filters enabled, you can manually disable them. For example:
+
+```java
+providerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+consumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");
+```
+
+or add setting in `rpc-config.json` file, and its priority is lower than above.
+
+```json
+{
+  "sofa.rpc.sentinel.enabled": true
+}
+```
+
+For more details of SOFARPC filter, see [here](https://www.sofastack.tech/projects/sofa-rpc/custom-filter/).
+
+## SOFARPC resources
+
+The resource for SOFARPC services has two granularities: service interface and service method.
+
+- Service interface:resourceName format is `interfaceName`,e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService`
+- Service method:resourceName format is `interfaceName#methodSignature`,e.g. `com.alibaba.csp.sentinel.demo.sofa.rpc.DemoService#sayHello(java.lang.Integer,java.lang.String,int)`
+
+## Flow control based on caller
+
+In many circumstances, it's also significant to control traffic flow based on the **caller**.
+For example, assuming that there are two services A and B, both of them initiate remote call requests to the service provider.
+If we want to limit the calls from service B only, we can set the `limitApp` of flow rule as the identifier of service B (e.g. service name).
+
+Sentinel SOFARPC Adapter will automatically resolve the SOFARPC consumer's *application name* as the caller's name (`origin`),
+and will bring the caller's name when doing resource protection.
+If `limitApp` of flow rules is not configured (`default`), flow control will take effects on all callers.
+If `limitApp` of a flow rule is configured with a caller, then the corresponding flow rule will only take effect on the specific caller.
+
+## Global fallback
+
+Sentinel SOFARPC Adapter supports global fallback configuration.
+The global fallback will handle exceptions and give replacement result when blocked by
+flow control, degrade or system load protection. You can implement your own `SofaRpcFallback` interface
+and then register to `SofaRpcFallbackRegistry`. If no fallback is configured, Sentinel will wrap the `BlockException`
+then directly throw it out.

+ 43 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/pom.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sentinel-adapter</artifactId>
+        <groupId>com.alibaba.csp</groupId>
+        <version>1.8.3</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sentinel-sofa-rpc-adapter</artifactId>
+
+    <properties>
+        <sofa-rpc-all.version>5.6.4</sofa-rpc-all.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alipay.sofa</groupId>
+            <artifactId>sofa-rpc-all</artifactId>
+            <version>${sofa-rpc-all.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

+ 72 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilter.java

@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alibaba.csp.sentinel.Entry;
+import com.alibaba.csp.sentinel.Tracer;
+
+import com.alipay.sofa.rpc.common.RpcConfigs;
+import com.alipay.sofa.rpc.common.utils.StringUtils;
+import com.alipay.sofa.rpc.config.AbstractInterfaceConfig;
+import com.alipay.sofa.rpc.core.exception.RpcErrorType;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.Filter;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * @author cdfive
+ */
+abstract class AbstractSofaRpcFilter extends Filter {
+
+    @Override
+    public boolean needToLoad(FilterInvoker invoker) {
+        AbstractInterfaceConfig<?, ?> config = invoker.getConfig();
+
+        String enabled = config.getParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED);
+        if (StringUtils.isNotBlank(enabled)) {
+            return Boolean.parseBoolean(enabled);
+        }
+
+        return RpcConfigs.getOrDefaultValue(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, true);
+    }
+
+    protected void traceResponseException(SofaResponse response, Entry interfaceEntry, Entry methodEntry) {
+        if (response.isError()) {
+            SofaRpcException rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, response.getErrorMsg());
+            Tracer.traceEntry(rpcException, interfaceEntry);
+            Tracer.traceEntry(rpcException, methodEntry);
+        } else {
+            Object appResponse = response.getAppResponse();
+            if (appResponse instanceof Throwable) {
+                Tracer.traceEntry((Throwable) appResponse, interfaceEntry);
+                Tracer.traceEntry((Throwable) appResponse, methodEntry);
+            }
+        }
+    }
+
+    protected SofaRpcException traceOtherException(Throwable t, Entry interfaceEntry, Entry methodEntry) {
+        SofaRpcException rpcException;
+        if (t instanceof SofaRpcException) {
+            rpcException = (SofaRpcException) t;
+        } else {
+            rpcException = new SofaRpcException(RpcErrorType.SERVER_FILTER, t);
+        }
+        Tracer.traceEntry(rpcException, interfaceEntry);
+        Tracer.traceEntry(rpcException, methodEntry);
+        return rpcException;
+    }
+}

+ 27 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelConstants.java

@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999-2020 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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
+ *
+ *      https://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 com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+/**
+ * @author cdfive
+ * @since 1.7.2
+ */
+public final class SentinelConstants {
+
+    public static final String SOFA_RPC_SENTINEL_ENABLED = "sofa.rpc.sentinel.enabled";
+
+    private SentinelConstants() {}
+}

+ 84 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcConsumerFilter.java

@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.Extension;
+import com.alipay.sofa.rpc.filter.AutoActive;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
+
+/**
+ * SOFARPC service consumer filter for Sentinel, auto activated by default.
+ *
+ * If you want to disable the consumer filter, you can configure:
+ * <pre>ConsumerConfig.setParameter("sofa.rpc.sentinel.enabled", "false");</pre>
+ *
+ * or add setting in rpc-config.json:
+ * <pre>"sofa.rpc.sentinel.enabled": false </pre>
+ *
+ * @author cdfive
+ */
+@Extension(value = "consumerSentinel", order = -1000)
+@AutoActive(consumerSide = true)
+public class SentinelSofaRpcConsumerFilter extends AbstractSofaRpcFilter {
+
+    @Override
+    public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
+        // Now only support sync invoke.
+        if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
+            return invoker.invoke(request);
+        }
+
+        String interfaceResourceName = getInterfaceResourceName(request);
+        String methodResourceName = getMethodResourceName(request);
+
+        Entry interfaceEntry = null;
+        Entry methodEntry = null;
+        try {
+            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
+            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC,
+                EntryType.OUT, getMethodArguments(request));
+
+            SofaResponse response = invoker.invoke(request);
+
+            traceResponseException(response, interfaceEntry, methodEntry);
+            return response;
+        } catch (BlockException e) {
+            return SofaRpcFallbackRegistry.getConsumerFallback().handle(invoker, request, e);
+        } catch (Throwable t) {
+            throw traceOtherException(t, interfaceEntry, methodEntry);
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit(1, getMethodArguments(request));
+            }
+
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+        }
+    }
+}

+ 93 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SentinelSofaRpcProviderFilter.java

@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback.SofaRpcFallbackRegistry;
+import com.alibaba.csp.sentinel.context.ContextUtil;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+
+import com.alipay.sofa.rpc.common.RpcConstants;
+import com.alipay.sofa.rpc.core.exception.SofaRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.ext.Extension;
+import com.alipay.sofa.rpc.filter.AutoActive;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getApplicationName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getInterfaceResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodResourceName;
+import static com.alibaba.csp.sentinel.adapter.sofa.rpc.SofaRpcUtils.getMethodArguments;
+
+/**
+ * SOFARPC service provider filter for Sentinel, auto activated by default.
+ *
+ * If you want to disable the provider filter, you can configure:
+ * <pre>ProviderConfig.setParameter("sofa.rpc.sentinel.enabled", "false");</pre>
+ *
+ * or add setting in rpc-config.json file:
+ * <pre>
+ * {
+ *   "sofa.rpc.sentinel.enabled": false
+ * }
+ * </pre>
+ *
+ * @author cdfive
+ */
+@Extension(value = "providerSentinel", order = -1000)
+@AutoActive(providerSide = true)
+public class SentinelSofaRpcProviderFilter extends AbstractSofaRpcFilter {
+
+    @Override
+    public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
+        // Now only support sync invoke.
+        if (request.getInvokeType() != null && !RpcConstants.INVOKER_TYPE_SYNC.equals(request.getInvokeType())) {
+            return invoker.invoke(request);
+        }
+
+        String callerApp = getApplicationName(request);
+        String interfaceResourceName = getInterfaceResourceName(request);
+        String methodResourceName = getMethodResourceName(request);
+
+        Entry interfaceEntry = null;
+        Entry methodEntry = null;
+        try {
+            ContextUtil.enter(methodResourceName, callerApp);
+
+            interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.IN);
+            methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC,
+                EntryType.IN, getMethodArguments(request));
+
+            SofaResponse response = invoker.invoke(request);
+
+            traceResponseException(response, interfaceEntry, methodEntry);
+            return response;
+        } catch (BlockException e) {
+            return SofaRpcFallbackRegistry.getProviderFallback().handle(invoker, request, e);
+        } catch (Throwable t) {
+            throw traceOtherException(t, interfaceEntry, methodEntry);
+        } finally {
+            if (methodEntry != null) {
+                methodEntry.exit(1, getMethodArguments(request));
+            }
+            if (interfaceEntry != null) {
+                interfaceEntry.exit();
+            }
+            ContextUtil.exit();
+        }
+    }
+}

+ 61 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/SofaRpcUtils.java

@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alipay.sofa.rpc.common.RemotingConstants;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+
+/**
+ * @author cdfive
+ */
+public class SofaRpcUtils {
+
+    public static String getApplicationName(SofaRequest request) {
+        String appName = (String) request.getRequestProp(RemotingConstants.HEAD_APP_NAME);
+        return appName == null ? "" : appName;
+    }
+
+    public static String getInterfaceResourceName(SofaRequest request) {
+        return request.getInterfaceName();
+    }
+
+    public static String getMethodResourceName(SofaRequest request) {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append(request.getInterfaceName())
+                .append("#")
+                .append(request.getMethodName())
+                .append("(");
+
+        boolean isFirst = true;
+        for (String methodArgSig : request.getMethodArgSigs()) {
+            if (!isFirst) {
+                buf.append(",");
+            } else {
+                isFirst = false;
+            }
+
+            buf.append(methodArgSig);
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    public static Object[] getMethodArguments(SofaRequest request) {
+        return request.getMethodArgs();
+    }
+
+    private SofaRpcUtils() {}
+}

+ 37 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/DefaultSofaRpcFallback.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * Default Sentinel fallback handler for SOFARPC services.
+ * Just wrap and throw the exception.
+ *
+ * @author cdfive
+ */
+public class DefaultSofaRpcFallback implements SofaRpcFallback {
+
+    @Override
+    public SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex) {
+        // Just wrap and throw the exception.
+        throw new SentinelRpcException(ex);
+    }
+}

+ 39 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallback.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+
+/**
+ * Sentinel fallback handler for SOFARPC services.
+ *
+ * @author cdfive
+ */
+public interface SofaRpcFallback {
+
+    /**
+     * Handle the block exception and provide fallback result.
+     *
+     * @param invoker FilterInvoker
+     * @param request SofaRequest
+     * @param ex block exception
+     * @return fallback result
+     */
+    SofaResponse handle(FilterInvoker invoker, SofaRequest request, BlockException ex);
+}

+ 50 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/fallback/SofaRpcFallbackRegistry.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed 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 com.alibaba.csp.sentinel.adapter.sofa.rpc.fallback;
+
+import com.alibaba.csp.sentinel.util.AssertUtil;
+
+/**
+ * Global Sentinel fallback registry for SOFARPC services.
+ *
+ * @author cdfive
+ */
+public final class SofaRpcFallbackRegistry {
+
+    private static volatile SofaRpcFallback providerFallback = new DefaultSofaRpcFallback();
+    private static volatile SofaRpcFallback consumerFallback = new DefaultSofaRpcFallback();
+
+    public static SofaRpcFallback getProviderFallback() {
+        return providerFallback;
+    }
+
+    public static void setProviderFallback(SofaRpcFallback providerFallback) {
+        AssertUtil.notNull(providerFallback, "providerFallback cannot be null");
+        SofaRpcFallbackRegistry.providerFallback = providerFallback;
+    }
+
+    public static SofaRpcFallback getConsumerFallback() {
+        return consumerFallback;
+    }
+
+    public static void setConsumerFallback(SofaRpcFallback consumerFallback) {
+        AssertUtil.notNull(consumerFallback, "consumerFallback cannot be null");
+        SofaRpcFallbackRegistry.consumerFallback = consumerFallback;
+    }
+
+    private SofaRpcFallbackRegistry() {}
+}
+

+ 3 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/main/resources/META-INF/services/sofa-rpc/com.alipay.sofa.rpc.filter.Filter

@@ -0,0 +1,3 @@
+# name                                                                        # order
+com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcProviderFilter       # -1000
+com.alibaba.csp.sentinel.adapter.sofa.rpc.SentinelSofaRpcConsumerFilter       # -1000

+ 108 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/AbstractSofaRpcFilterTest.java

@@ -0,0 +1,108 @@
+package com.alibaba.csp.sentinel.adapter.sofa.rpc;
+
+import com.alipay.sofa.rpc.codec.Serializer;
+import com.alipay.sofa.rpc.common.RpcConfigs;
+import com.alipay.sofa.rpc.config.ConsumerConfig;
+import com.alipay.sofa.rpc.config.ProviderConfig;
+import com.alipay.sofa.rpc.filter.FilterInvoker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test cases for {@link AbstractSofaRpcFilter}.
+ *
+ * @author cdfive
+ */
+public class AbstractSofaRpcFilterTest {
+
+    @Before
+    public void setUp() {
+        removeRpcConfig(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED);
+    }
+
+    @After
+    public void cleanUp() {
+        removeRpcConfig(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED);
+    }
+
+    @Test
+    public void testNeedToLoadProvider() {
+        SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
+        ProviderConfig providerConfig = new ProviderConfig();
+        providerConfig.setInterfaceId(Serializer.class.getName());
+        providerConfig.setId("AAA");
+        FilterInvoker invoker = new FilterInvoker(null, null, providerConfig);
+        assertTrue(providerFilter.needToLoad(invoker));
+
+        providerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(providerFilter.needToLoad(invoker));
+
+        providerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "");
+        assertTrue(providerFilter.needToLoad(invoker));
+
+        RpcConfigs.putValue(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(providerFilter.needToLoad(invoker));
+    }
+
+    @Test
+    public void testNeedToLoadConsumer() {
+        SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
+        ConsumerConfig consumerConfig = new ConsumerConfig();
+        consumerConfig.setInterfaceId(Serializer.class.getName());
+        consumerConfig.setId("BBB");
+        FilterInvoker invoker = new FilterInvoker(null, null, consumerConfig);
+        assertTrue(consumerFilter.needToLoad(invoker));
+
+        consumerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(consumerFilter.needToLoad(invoker));
+
+        consumerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "");
+        assertTrue(consumerFilter.needToLoad(invoker));
+
+        RpcConfigs.putValue(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(consumerFilter.needToLoad(invoker));
+    }
+
+    @Test
+    public void testNeedToLoadProviderAndConsumer() {
+        SentinelSofaRpcProviderFilter providerFilter = new SentinelSofaRpcProviderFilter();
+        ProviderConfig providerConfig = new ProviderConfig();
+        providerConfig.setInterfaceId(Serializer.class.getName());
+        providerConfig.setId("AAA");
+        FilterInvoker providerInvoker = new FilterInvoker(null, null, providerConfig);
+        assertTrue(providerFilter.needToLoad(providerInvoker));
+
+        SentinelSofaRpcConsumerFilter consumerFilter = new SentinelSofaRpcConsumerFilter();
+        ConsumerConfig consumerConfig = new ConsumerConfig();
+        consumerConfig.setInterfaceId(Serializer.class.getName());
+        consumerConfig.setId("BBB");
+        FilterInvoker consumerInvoker = new FilterInvoker(null, null, consumerConfig);
+        assertTrue(consumerFilter.needToLoad(consumerInvoker));
+
+        providerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(providerFilter.needToLoad(providerInvoker));
+        assertTrue(consumerFilter.needToLoad(consumerInvoker));
+
+        providerConfig.setParameter(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "");
+        assertTrue(providerFilter.needToLoad(providerInvoker));
+
+        RpcConfigs.putValue(SentinelConstants.SOFA_RPC_SENTINEL_ENABLED, "false");
+        assertFalse(providerFilter.needToLoad(providerInvoker));
+        assertFalse(consumerFilter.needToLoad(consumerInvoker));
+    }
+
+    private void removeRpcConfig(String key) {
+        try {
+            Method removeValueMethod = RpcConfigs.class.getDeclaredMethod("removeValue", String.class);
+            removeValueMethod.setAccessible(true);
+            removeValueMethod.invoke(null, key);
+        } catch (Exception e) {
+            // Empty
+        }
+    }
+}

+ 0 - 0
sentinel-adapter/sentinel-sofa-rpc-adapter/src/test/java/com/alibaba/csp/sentinel/adapter/sofa/rpc/BaseTest.java


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio