This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 6de804859c4dd91c9351a71e6bbed0b2aa3f413b
Author: liubao <[email protected]>
AuthorDate: Mon Jan 4 09:16:57 2021 +0800

    [SCB-2116]add provider implementation and refactor some api
---
 .../foundation/common/utils/BeanUtils.java         |   8 ++
 .../apache/servicecomb/governance/GovManager.java  |  87 --------------
 ...Handler.java => AbstractGovernanceHandler.java} |  17 ++-
 .../governance/handler/BulkheadHandler.java        |  16 +--
 .../governance/handler/CircuitBreakerHandler.java  |  23 +---
 .../servicecomb/governance/handler/GovHandler.java |  28 -----
 .../governance/handler/RateLimitingHandler.java    |  21 +---
 .../governance/handler/RetryHandler.java           |  21 +---
 .../servicecomb/governance/FlowControlTest.java    |  13 +-
 .../governance/GovernancePropertiesTest.java       |  29 ++---
 handlers/handler-governance/README.md              |   3 +
 handlers/handler-governance/pom.xml                |  65 ++++++++++
 .../governance/ProviderGovernanceHandler.java      | 132 +++++++++++++++++++++
 ....servicecomb.registry.discovery.DiscoveryFilter |  17 +++
 .../src/main/resources/config/cse.handler.xml      |  21 ++++
 handlers/pom.xml                                   |   1 +
 16 files changed, 301 insertions(+), 201 deletions(-)

diff --git 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
index fc7606e..4e58615 100644
--- 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
+++ 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/utils/BeanUtils.java
@@ -141,6 +141,14 @@ public final class BeanUtils {
     return context.getBeansOfType(type);
   }
 
+  public static <T> T getBean(Class<T> type) {
+    if (context == null) {
+      // for some test case
+      return null;
+    }
+    return context.getBean(type);
+  }
+
   /**
    * Get the implemented class of the given instance
    * @param bean the instance to get implemented class from
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java 
b/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java
deleted file mode 100644
index e3752e3..0000000
--- a/governance/src/main/java/org/apache/servicecomb/governance/GovManager.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.governance;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.servicecomb.governance.handler.GovHandler;
-import org.apache.servicecomb.governance.handler.HandlerType;
-import org.apache.servicecomb.governance.handler.ext.ClientRecoverPolicy;
-import org.apache.servicecomb.governance.handler.ext.ServerRecoverPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import io.github.resilience4j.decorators.Decorators;
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
-import io.vavr.CheckedFunction0;
-import io.vavr.control.Try;
-
-@Component
-public class GovManager {
-
-  @Autowired
-  Map<String, GovHandler> handlers;
-
-  @Autowired(required = false)
-  ServerRecoverPolicy<Object> serverRecoverPolicy;
-
-  @Autowired(required = false)
-  ClientRecoverPolicy<Object> clientRecoverPolicy;
-
-  public Object processServer(List<Policy> policies, CheckedFunction0<Object> 
supplier) {
-    DecorateCheckedSupplier<Object> ds = 
Decorators.ofCheckedSupplier(supplier);
-    for (Policy policy : policies) {
-      if (handlers.get(policy.handler()) == null ||
-          handlers.get(policy.handler()).type() == HandlerType.CLIENT) {
-        continue;
-      }
-      ds = handlers.get(policy.handler()).process(ds, policy);
-    }
-
-    Try<Object> of = Try.of(ds.decorate());
-    return of
-        .recover(throwable -> {
-          if (serverRecoverPolicy == null) {
-            throw (RuntimeException) throwable;
-          } else {
-            return serverRecoverPolicy.apply(throwable);
-          }
-        }).get();
-  }
-
-  public Object processClient(List<Policy> policies, CheckedFunction0<Object> 
supplier) {
-    DecorateCheckedSupplier<Object> ds = 
Decorators.ofCheckedSupplier(supplier);
-    for (Policy policy : policies) {
-      if (handlers.get(policy.handler()) == null ||
-          handlers.get(policy.handler()).type() == HandlerType.SERVER) {
-        continue;
-      }
-      ds = handlers.get(policy.handler()).process(ds, policy);
-    }
-    Try<Object> of = Try.of(ds.decorate());
-    return of
-        .recover(throwable -> {
-          if (clientRecoverPolicy == null) {
-            throw (RuntimeException) throwable;
-          } else {
-            return clientRecoverPolicy.apply(throwable);
-          }
-        }).get();
-  }
-}
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
similarity index 80%
rename from 
governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java
rename to 
governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
index a6f008e..1cb55d1 100644
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovHandler.java
+++ 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/AbstractGovernanceHandler.java
@@ -19,28 +19,33 @@ package org.apache.servicecomb.governance.handler;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
 
-import com.google.common.eventbus.Subscribe;
 import org.apache.servicecomb.governance.event.ConfigurationChangedEvent;
 import org.apache.servicecomb.governance.event.EventManager;
 
-public abstract class AbstractGovHandler<PROCESSOR> implements GovHandler {
+import com.google.common.eventbus.Subscribe;
+
+public abstract class AbstractGovernanceHandler<PROCESSOR, POLICY> {
   private Map<String, PROCESSOR> map = new ConcurrentHashMap<>();
 
-  protected AbstractGovHandler() {
+  protected AbstractGovernanceHandler() {
     EventManager.register(this);
   }
 
-  protected <R> PROCESSOR getActuator(String key, R policy, Function<R, 
PROCESSOR> func) {
+  public <R> PROCESSOR getActuator(POLICY policy) {
+    String key = createKey(policy);
     PROCESSOR processor = map.get(key);
     if (processor == null) {
-      processor = func.apply(policy);
+      processor = createProcessor(policy);
       map.put(key, processor);
     }
     return processor;
   }
 
+  abstract protected String createKey(POLICY policy);
+
+  abstract protected PROCESSOR createProcessor(POLICY policy);
+
   @Subscribe
   public void onDynamicConfigurationListener(ConfigurationChangedEvent event) {
     event.getChangedConfigurations().forEach(v -> map.remove(v));
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
index df99d93..c5b2497 100644
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
+++ 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/BulkheadHandler.java
@@ -19,32 +19,28 @@ package org.apache.servicecomb.governance.handler;
 
 import java.time.Duration;
 
+import org.apache.servicecomb.governance.policy.BulkheadPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.policy.BulkheadPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-
 import io.github.resilience4j.bulkhead.Bulkhead;
 import io.github.resilience4j.bulkhead.BulkheadConfig;
 import io.github.resilience4j.bulkhead.BulkheadRegistry;
 import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
 
 @Component("BulkheadHandler")
-public class BulkheadHandler extends AbstractGovHandler<Bulkhead> {
+public class BulkheadHandler extends AbstractGovernanceHandler<Bulkhead, 
BulkheadPolicy> {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(BulkheadHandler.class);
 
   @Override
-  public <RESULT> DecorateCheckedSupplier<RESULT> 
process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
-    Bulkhead bulkhead = getActuator("servicecomb.bulkhead." + policy.name(), 
(BulkheadPolicy) policy,
-        this::getBulkhead);
-    return supplier.withBulkhead(bulkhead);
+  protected String createKey(BulkheadPolicy policy) {
+    return "servicecomb.bulkhead." + policy.name();
   }
 
   @Override
-  public HandlerType type() {
-    return HandlerType.SERVER;
+  protected Bulkhead createProcessor(BulkheadPolicy policy) {
+    return getBulkhead(policy);
   }
 
   private Bulkhead getBulkhead(BulkheadPolicy policy) {
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
index 91dfdf9..d041edc 100644
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
+++ 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/CircuitBreakerHandler.java
@@ -18,40 +18,29 @@ package org.apache.servicecomb.governance.handler;
 
 import java.time.Duration;
 
+import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
-import org.apache.servicecomb.governance.policy.Policy;
-
 import io.github.resilience4j.circuitbreaker.CircuitBreaker;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
 import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
 
 @Component("CircuitBreakerHandler")
-public class CircuitBreakerHandler extends AbstractGovHandler<CircuitBreaker> {
+public class CircuitBreakerHandler extends 
AbstractGovernanceHandler<CircuitBreaker, CircuitBreakerPolicy> {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(CircuitBreakerHandler.class);
 
   @Override
-  public <RESULT> DecorateCheckedSupplier<RESULT> 
process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
-    CircuitBreaker circuitBreaker = getActuator("servicecomb.circuitBreaker." 
+ policy.name(),
-        (CircuitBreakerPolicy) policy, this::getCircuitBreaker);
-    return supplier.withCircuitBreaker(circuitBreaker);
+  protected String createKey(CircuitBreakerPolicy policy) {
+    return "servicecomb.circuitBreaker." + policy.name();
   }
 
   @Override
-  public HandlerType type() {
-    return HandlerType.SERVER;
+  protected CircuitBreaker createProcessor(CircuitBreakerPolicy policy) {
+    return getCircuitBreaker(policy);
   }
 
-  /**
-   * todo: recordExceptions
-   *
-   * @param policy
-   * @return
-   */
   private CircuitBreaker getCircuitBreaker(CircuitBreakerPolicy policy) {
     LOGGER.info("applying new policy: {}", policy.toString());
 
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java
deleted file mode 100644
index 81a9611..0000000
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/GovHandler.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.servicecomb.governance.handler;
-
-import org.apache.servicecomb.governance.policy.Policy;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
-
-public interface GovHandler {
-
-  <RESULT> DecorateCheckedSupplier<RESULT> 
process(DecorateCheckedSupplier<RESULT> supplier, Policy policy);
-
-  HandlerType type();
-}
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
index 82a271a..dcdb5d8 100644
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
+++ 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/RateLimitingHandler.java
@@ -18,38 +18,29 @@ package org.apache.servicecomb.governance.handler;
 
 import java.time.Duration;
 
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.policy.Policy;
-import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
 import io.github.resilience4j.ratelimiter.RateLimiter;
 import io.github.resilience4j.ratelimiter.RateLimiterConfig;
 import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
 
 @Component("RateLimitingHandler")
-public class RateLimitingHandler extends AbstractGovHandler<RateLimiter> {
+public class RateLimitingHandler extends 
AbstractGovernanceHandler<RateLimiter, RateLimitingPolicy> {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(RateLimitingHandler.class);
 
   @Override
-  public <RESULT> DecorateCheckedSupplier<RESULT> 
process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
-    RateLimiter rateLimiter = getActuator("servicecomb.rateLimiting." + 
policy.name(), (RateLimitingPolicy) policy,
-        this::getRateLimiter);
-    return supplier.withRateLimiter(rateLimiter);
+  protected String createKey(RateLimitingPolicy policy) {
+    return "servicecomb.rateLimiting." + policy.name();
   }
 
   @Override
-  public HandlerType type() {
-    return HandlerType.SERVER;
+  protected RateLimiter createProcessor(RateLimitingPolicy policy) {
+    return getRateLimiter(policy);
   }
 
-  /**
-   * @param policy
-   * @return
-   */
   private RateLimiter getRateLimiter(RateLimitingPolicy policy) {
     LOGGER.info("applying new policy: {}", policy.toString());
 
diff --git 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
index 86b902d..068bb55 100644
--- 
a/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
+++ 
b/governance/src/main/java/org/apache/servicecomb/governance/handler/RetryHandler.java
@@ -22,42 +22,33 @@ import java.util.List;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.handler.ext.RetryExtension;
 import org.apache.servicecomb.governance.policy.RetryPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import org.apache.servicecomb.governance.handler.ext.RetryExtension;
-
-import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
 import io.github.resilience4j.retry.Retry;
 import io.github.resilience4j.retry.RetryConfig;
 import io.github.resilience4j.retry.RetryRegistry;
 
 @Component("RetryHandler")
-public class RetryHandler extends AbstractGovHandler<Retry> {
+public class RetryHandler extends AbstractGovernanceHandler<Retry, 
RetryPolicy> {
 
   private static final Logger LOGGER = 
LoggerFactory.getLogger(RetryHandler.class);
 
   @Autowired
   private RetryExtension retryExtension;
 
-  /**
-   * @param supplier
-   * @param policy
-   * @return
-   */
   @Override
-  public <RESULT> DecorateCheckedSupplier<RESULT> 
process(DecorateCheckedSupplier<RESULT> supplier, Policy policy) {
-    Retry retry = getActuator("servicecomb.retry." + policy.name(), 
(RetryPolicy) policy, this::getRetry);
-    return supplier.withRetry(retry);
+  protected String createKey(RetryPolicy policy) {
+    return "servicecomb.retry." + policy.name();
   }
 
   @Override
-  public HandlerType type() {
-    return HandlerType.CLIENT;
+  protected Retry createProcessor(RetryPolicy policy) {
+    return getRetry(policy);
   }
 
   private Retry getRetry(RetryPolicy retryPolicy) {
diff --git 
a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
 
b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
index 8aeddba..e16dafa 100644
--- 
a/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
+++ 
b/governance/src/test/java/org/apache/servicecomb/governance/FlowControlTest.java
@@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.servicecomb.governance.handler.RateLimitingHandler;
 import org.apache.servicecomb.governance.marker.GovHttpRequest;
-import org.apache.servicecomb.governance.policy.Policy;
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
 import org.apache.servicecomb.governance.properties.RateLimitProperties;
 import org.junit.Assert;
 import org.junit.Test;
@@ -35,6 +35,7 @@ import org.springframework.test.context.junit4.SpringRunner;
 
 import io.github.resilience4j.decorators.Decorators;
 import io.github.resilience4j.decorators.Decorators.DecorateCheckedSupplier;
+import io.github.resilience4j.ratelimiter.RateLimiter;
 import io.github.resilience4j.ratelimiter.RequestNotPermitted;
 
 @RunWith(SpringRunner.class)
@@ -57,11 +58,12 @@ public class FlowControlTest {
 
     GovHttpRequest request = new GovHttpRequest("testService", "1.0");
     request.setUri("/hello");
-    Policy policy = matchersManager.match(request, 
rateLimitProperties.getParsedEntity());
+    RateLimitingPolicy policy = matchersManager.match(request, 
rateLimitProperties.getParsedEntity());
     Assert.assertNotNull(policy);
-    DecorateCheckedSupplier<Object> dcs = rateLimitingHandler.process(ds, 
policy);
+    RateLimiter rateLimiter = rateLimitingHandler.getActuator(policy);
+    ds.withRateLimiter(rateLimiter);
 
-    Assert.assertEquals("test", dcs.get());
+    Assert.assertEquals("test", ds.get());
 
     // flow control
     CountDownLatch cd = new CountDownLatch(10);
@@ -71,8 +73,7 @@ public class FlowControlTest {
       new Thread() {
         public void run() {
           try {
-            DecorateCheckedSupplier<Object> dcs = 
rateLimitingHandler.process(ds, policy);
-            Object result = dcs.get();
+            Object result = ds.get();
             if (!"test".equals(result)) {
               notExpected.set(true);
             }
diff --git 
a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
 
b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
index 560bf05..971a09d 100644
--- 
a/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
+++ 
b/governance/src/test/java/org/apache/servicecomb/governance/GovernancePropertiesTest.java
@@ -23,19 +23,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import 
org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
-import org.springframework.core.env.ConfigurableEnvironment;
-import org.springframework.core.env.EnumerablePropertySource;
-import org.springframework.core.env.Environment;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-
 import org.apache.servicecomb.governance.event.ConfigurationChangedEvent;
 import org.apache.servicecomb.governance.event.EventManager;
 import org.apache.servicecomb.governance.marker.Matcher;
@@ -51,6 +38,18 @@ import 
org.apache.servicecomb.governance.properties.GovernanceProperties;
 import org.apache.servicecomb.governance.properties.MatchProperties;
 import org.apache.servicecomb.governance.properties.RateLimitProperties;
 import org.apache.servicecomb.governance.properties.RetryProperties;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import 
org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
 
 @RunWith(SpringRunner.class)
 @ContextConfiguration(locations = "classpath:META-INF/spring/*.xml", 
initializers = ConfigFileApplicationContextInitializer.class)
@@ -79,10 +78,6 @@ public class GovernancePropertiesTest {
 
   private Map<String, Object> dynamicValues = new HashMap<>();
 
-  public GovernancePropertiesTest() {
-    System.out.print(1);
-  }
-
   @Before
   public void setUp() {
     ConfigurableEnvironment configurableEnvironment = 
(ConfigurableEnvironment) environment;
diff --git a/handlers/handler-governance/README.md 
b/handlers/handler-governance/README.md
new file mode 100644
index 0000000..3a9db2f
--- /dev/null
+++ b/handlers/handler-governance/README.md
@@ -0,0 +1,3 @@
+Enable governance features by handler. 
+
+Governance can be enabled in any different process layer, enable it in handler 
is most portable way.
\ No newline at end of file
diff --git a/handlers/handler-governance/pom.xml 
b/handlers/handler-governance/pom.xml
new file mode 100644
index 0000000..26aa4c6
--- /dev/null
+++ b/handlers/handler-governance/pom.xml
@@ -0,0 +1,65 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>org.apache.servicecomb</groupId>
+    <artifactId>handlers</artifactId>
+    <version>2.1.5-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>handler-governance</artifactId>
+  <name>Java Chassis::Handlers::Governance</name>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>java-chassis-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>servicecomb-governance</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>registry-local</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>foundation-test-scaffolding</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git 
a/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java
 
b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java
new file mode 100644
index 0000000..06d0c50
--- /dev/null
+++ 
b/handlers/handler-governance/src/main/java/org/apache/servicecomb/handler/governance/ProviderGovernanceHandler.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.handler.governance;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Supplier;
+
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.utils.BeanUtils;
+import org.apache.servicecomb.governance.MatchersManager;
+import org.apache.servicecomb.governance.handler.BulkheadHandler;
+import org.apache.servicecomb.governance.handler.CircuitBreakerHandler;
+import org.apache.servicecomb.governance.handler.RateLimitingHandler;
+import org.apache.servicecomb.governance.marker.GovHttpRequest;
+import org.apache.servicecomb.governance.policy.BulkheadPolicy;
+import org.apache.servicecomb.governance.policy.CircuitBreakerPolicy;
+import org.apache.servicecomb.governance.policy.RateLimitingPolicy;
+import org.apache.servicecomb.governance.properties.BulkheadProperties;
+import org.apache.servicecomb.governance.properties.CircuitBreakerProperties;
+import org.apache.servicecomb.governance.properties.RateLimitProperties;
+import org.apache.servicecomb.registry.RegistrationManager;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.github.resilience4j.bulkhead.BulkheadFullException;
+import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
+import io.github.resilience4j.decorators.Decorators;
+import io.github.resilience4j.decorators.Decorators.DecorateCompletionStage;
+import io.github.resilience4j.ratelimiter.RequestNotPermitted;
+
+public class ProviderGovernanceHandler implements Handler {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ProviderGovernanceHandler.class);
+
+  private MatchersManager matchersManager = 
BeanUtils.getBean(MatchersManager.class);
+
+  private RateLimitingHandler rateLimitingHandler = 
BeanUtils.getBean(RateLimitingHandler.class);
+
+  private RateLimitProperties rateLimitProperties = 
BeanUtils.getBean(RateLimitProperties.class);
+
+  private CircuitBreakerHandler circuitBreakerHandler = 
BeanUtils.getBean(CircuitBreakerHandler.class);
+
+  private CircuitBreakerProperties circuitBreakerProperties = 
BeanUtils.getBean(CircuitBreakerProperties.class);
+
+  private BulkheadHandler bulkheadHandler = 
BeanUtils.getBean(BulkheadHandler.class);
+
+  private BulkheadProperties bulkheadProperties = 
BeanUtils.getBean(BulkheadProperties.class);
+
+  @Override
+  public void handle(Invocation invocation, AsyncResponse asyncResp) throws 
Exception {
+
+    Supplier<CompletionStage<Response>> next = 
createBusinessCompletionStageSupplier(invocation);
+    DecorateCompletionStage<Response> dcs = Decorators.ofCompletionStage(next);
+    GovHttpRequest request = createGovHttpRequest(invocation);
+
+    RateLimitingPolicy rateLimitingPolicy = matchersManager.match(request, 
rateLimitProperties.getParsedEntity());
+    dcs.withRateLimiter(rateLimitingHandler.getActuator(rateLimitingPolicy));
+    CircuitBreakerPolicy circuitBreakerPolicy = matchersManager
+        .match(request, circuitBreakerProperties.getParsedEntity());
+    
dcs.withCircuitBreaker(circuitBreakerHandler.getActuator(circuitBreakerPolicy));
+    BulkheadPolicy bulkheadPolicy = matchersManager.match(request, 
bulkheadProperties.getParsedEntity());
+    dcs.withBulkhead(bulkheadHandler.getActuator(bulkheadPolicy));
+
+    dcs.get().whenComplete((r, e) -> {
+      if (e == null) {
+        asyncResp.complete(r);
+        return;
+      }
+
+      if (e instanceof RequestNotPermitted) {
+        asyncResp.complete(
+            Response.failResp(new InvocationException(429, "rate limited.", 
new CommonExceptionData("rate limited."))));
+        LOGGER.warn("the request is rate limit by policy : {}", 
e.getMessage());
+      } else if (e instanceof CallNotPermittedException) {
+        asyncResp.complete(
+            Response.failResp(new InvocationException(429, "circuitBreaker is 
open.",
+                new CommonExceptionData("circuitBreaker is open."))));
+        LOGGER.warn("circuitBreaker is open by policy : {}", e.getMessage());
+      } else if (e instanceof BulkheadFullException) {
+        asyncResp.complete(
+            Response.failResp(new InvocationException(429, "bulkhead is full 
and does not permit further calls.",
+                new CommonExceptionData("bulkhead is full and does not permit 
further calls."))));
+        LOGGER.warn("bulkhead is full and does not permit further calls by 
policy : {}", e.getMessage());
+      } else {
+        asyncResp.complete(Response.createProducerFail(e));
+      }
+    });
+  }
+
+  private Supplier<CompletionStage<Response>> 
createBusinessCompletionStageSupplier(Invocation invocation) {
+    return () -> {
+      CompletableFuture<Response> result = new CompletableFuture<>();
+      try {
+        invocation.next(response -> {
+          result.complete(response);
+        });
+      } catch (Exception e) {
+        result.completeExceptionally(e);
+      }
+      return result;
+    };
+  }
+
+  private GovHttpRequest createGovHttpRequest(Invocation invocation) {
+    GovHttpRequest request = new 
GovHttpRequest(RegistrationManager.INSTANCE.getMicroservice().getServiceName(),
+        RegistrationManager.INSTANCE.getMicroservice().getVersion());
+    request.setUri(invocation.getSchemaId() + "." + 
invocation.getOperationName());
+    request.setMethod(invocation.getOperationMeta().getHttpMethod());
+    request.setHeaders(invocation.getContext());
+    return request;
+  }
+}
diff --git 
a/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter
 
b/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter
new file mode 100644
index 0000000..6222972
--- /dev/null
+++ 
b/handlers/handler-governance/src/main/resources/META-INF/services/org.apache.servicecomb.registry.discovery.DiscoveryFilter
@@ -0,0 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
diff --git 
a/handlers/handler-governance/src/main/resources/config/cse.handler.xml 
b/handlers/handler-governance/src/main/resources/config/cse.handler.xml
new file mode 100644
index 0000000..f99f63d
--- /dev/null
+++ b/handlers/handler-governance/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<config>
+  <handler id="governance-provider"
+    
class="org.apache.servicecomb.handler.governance.ProviderGovernanceHandler"/>
+</config>
diff --git a/handlers/pom.xml b/handlers/pom.xml
index 2d5bb2f..c5cea16 100644
--- a/handlers/pom.xml
+++ b/handlers/pom.xml
@@ -39,6 +39,7 @@
     <module>handler-fault-injection</module>
     <module>handler-publickey-auth</module>
     <module>handler-router</module>
+    <module>handler-governance</module>
   </modules>
 
 </project>

Reply via email to