You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jo...@apache.org on 2017/12/27 01:14:27 UTC

geronimo-safeguard git commit: GERONIMO-6582 Adding validation of method signatures via MicroProfile.

Repository: geronimo-safeguard
Updated Branches:
  refs/heads/master 5b7ccac68 -> 27626ffdf


GERONIMO-6582 Adding validation of method signatures via MicroProfile.

Upgrading test dependencies.


Project: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/repo
Commit: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/commit/27626ffd
Tree: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/tree/27626ffd
Diff: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/diff/27626ffd

Branch: refs/heads/master
Commit: 27626ffdfed0f609294b95d790e767e0a1f10daa
Parents: 5b7ccac
Author: John D. Ament <jo...@apache.org>
Authored: Sun Dec 24 21:44:09 2017 -0500
Committer: John D. Ament <jo...@apache.org>
Committed: Tue Dec 26 20:10:12 2017 -0500

----------------------------------------------------------------------
 pom.xml                                         |   4 +-
 .../impl/cdi/MicroProfileValidator.java         | 143 +++++++++++++++++++
 .../safeguard/impl/cdi/SafeguardExtension.java  |  14 +-
 .../MicroprofileAnnotationMapper.java           |   3 +
 .../safeguard/impl/util/AnnotationUtil.java     |  12 ++
 safeguard-tck-tests/pom.xml                     |  17 ---
 6 files changed, 170 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a3f1561..816ee06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,8 +55,8 @@
         <maven.compiler.target>1.8</maven.compiler.target>
         <microprofile-fault-tolerance.version>1.0</microprofile-fault-tolerance.version>
         <owb.version>2.0.1</owb.version>
-        <arquillian.version>1.1.13.Final</arquillian.version>
-        <arquillian-weld-embedded.version>2.0.0.Beta5</arquillian-weld-embedded.version>
+        <arquillian.version>1.1.14.Final</arquillian.version>
+        <arquillian-weld-embedded.version>2.0.0.Final</arquillian-weld-embedded.version>
         <cdi2-api.version>2.0</cdi2-api.version>
         <weld.version>3.0.1.Final</weld.version>
     </properties>

http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/MicroProfileValidator.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/MicroProfileValidator.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/MicroProfileValidator.java
new file mode 100644
index 0000000..714818b
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/MicroProfileValidator.java
@@ -0,0 +1,143 @@
+/*
+ *  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.safeguard.impl.cdi;
+
+import org.apache.safeguard.exception.SafeguardException;
+import org.apache.safeguard.impl.util.AnnotationUtil;
+import org.eclipse.microprofile.faulttolerance.Bulkhead;
+import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
+import org.eclipse.microprofile.faulttolerance.ExecutionContext;
+import org.eclipse.microprofile.faulttolerance.Fallback;
+import org.eclipse.microprofile.faulttolerance.Retry;
+import org.eclipse.microprofile.faulttolerance.Timeout;
+
+import javax.enterprise.inject.Vetoed;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import java.lang.reflect.Method;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+
+@Vetoed
+final class MicroProfileValidator {
+    private List<Throwable> capturedThrowables = new ArrayList<>();
+
+    void parse(AnnotatedType<?> annotatedType) {
+        for(AnnotatedMethod<?> method : annotatedType.getMethods()) {
+            Retry retry = AnnotationUtil.getAnnotation(method, annotatedType, Retry.class);
+            if (retry != null) {
+                validateRetry(retry, method);
+            }
+            Bulkhead bulkhead = AnnotationUtil.getAnnotation(method, annotatedType, Bulkhead.class);
+            if (bulkhead != null) {
+                validateBulkhead(bulkhead, method);
+            }
+            Timeout timeout = AnnotationUtil.getAnnotation(method, annotatedType, Timeout.class);
+            if (timeout != null) {
+                validateTimeout(timeout, method);
+            }
+            CircuitBreaker circuitBreaker = AnnotationUtil.getAnnotation(method, annotatedType, CircuitBreaker.class);
+            if (circuitBreaker != null) {
+                validateCircuitBreaker(circuitBreaker, method);
+            }
+            Fallback fallback = AnnotationUtil.getAnnotation(method, annotatedType, Fallback.class);
+            if (fallback != null) {
+                validateFallback(fallback, method, annotatedType);
+            }
+        }
+    }
+
+    private void validateFallback(Fallback fallback, AnnotatedMethod<?> method, AnnotatedType<?> annotatedType) {
+        if(fallback.fallbackMethod().equals("") && fallback.value().equals(Fallback.DEFAULT.class)) {
+            capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method));
+        }
+        else if(!fallback.fallbackMethod().equals("") && !fallback.value().equals(Fallback.DEFAULT.class)) {
+            capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method));
+        }
+        else if(!fallback.fallbackMethod().equals("")) {
+            boolean found = false;
+            for(AnnotatedMethod<?> otherMethod : annotatedType.getMethods()) {
+                if(otherMethod.getJavaMember().getName().equals(fallback.fallbackMethod())) {
+                    found = true;
+                    if(!method.getJavaMember().getReturnType().equals(otherMethod.getJavaMember().getReturnType())) {
+                        capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method +
+                                " wrong return type"));
+                    } else if(!Arrays.equals(method.getJavaMember().getParameterTypes(), otherMethod.getJavaMember().getParameterTypes())) {
+                        capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method +
+                                " wrong parameters"));
+                    }
+                }
+            }
+            if (!found) {
+                capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method +
+                        " fallback method not found"));
+            }
+        }
+        else {
+            try {
+                Method methodHandle = fallback.value().getMethod("handle", ExecutionContext.class);
+                if(!methodHandle.getReturnType().equals(method.getJavaMember().getReturnType())) {
+                    capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method +
+                            " wrong return type"));
+                }
+            } catch (NoSuchMethodException e) {
+                capturedThrowables.add(new SafeguardException("Invalid Fallback definition on method " + method +
+                        " fallback method not found"));
+            }
+        }
+    }
+
+    private void validateTimeout(Timeout timeout, AnnotatedMethod<?> method) {
+        if(timeout.value() < 0) {
+            capturedThrowables.add(new SafeguardException("Invalid Timeout definition on method " + method));
+        }
+    }
+
+    private void validateCircuitBreaker(CircuitBreaker circuitBreaker, AnnotatedMethod<?> method) {
+        if(circuitBreaker.requestVolumeThreshold() <= 0 || circuitBreaker.delay() < 0 || circuitBreaker.failureRatio() < 0.0
+                || circuitBreaker.failureRatio() > 1.0 || circuitBreaker.successThreshold() <= 0) {
+            capturedThrowables.add(new SafeguardException("Invalid CircuitBreaker definition on method " + method));
+        }
+    }
+
+    private void validateRetry(Retry retry, AnnotatedMethod<?> method) {
+        if(retry.jitter() < 0 || retry.maxDuration() < 0 || retry.delay() < 0 || retry.maxRetries() < 0) {
+            capturedThrowables.add(new SafeguardException("Invalid Retry definition on method " + method));
+        }
+        Duration delay = Duration.of(retry.delay(), retry.delayUnit());
+        Duration maxDuration = Duration.of(retry.maxDuration(), retry.durationUnit());
+        if(maxDuration.compareTo(delay) < 0) {
+            capturedThrowables.add(new SafeguardException("Invalid Retry definition on method " + method));
+        }
+    }
+
+    private void validateBulkhead(Bulkhead bulkhead, AnnotatedMethod<?> method) {
+        if(bulkhead.value() < 0 || bulkhead.waitingTaskQueue() < 0) {
+            capturedThrowables.add(new SafeguardException("Invalid Bulkhead definition on method " + method));
+        }
+    }
+
+    void forThrowable(Consumer<Throwable> consumer) {
+        capturedThrowables.forEach(consumer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
index c532914..0bd2e9d 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardExtension.java
@@ -26,6 +26,7 @@ import org.eclipse.microprofile.faulttolerance.Retry;
 import org.eclipse.microprofile.faulttolerance.Timeout;
 
 import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
 import javax.enterprise.inject.spi.AnnotatedConstructor;
 import javax.enterprise.inject.spi.AnnotatedField;
 import javax.enterprise.inject.spi.AnnotatedMethod;
@@ -42,12 +43,17 @@ import java.util.Set;
 import static org.apache.safeguard.api.SafeguardEnabled.INSTANCE;
 
 public class SafeguardExtension implements Extension {
-    public void findFaultTolerantBeans(@Observes @WithAnnotations({Retry.class, CircuitBreaker.class, Timeout.class,
-            Bulkhead.class})
-                                               ProcessAnnotatedType<?> pat) {
+    private MicroProfileValidator microProfileValidator = new MicroProfileValidator();
+    public <X> void findFaultTolerantBeans(@Observes @WithAnnotations({Retry.class, CircuitBreaker.class, Timeout.class,
+            Bulkhead.class}) ProcessAnnotatedType<X> pat) {
         if (!pat.getAnnotatedType().isAnnotationPresent(SafeguardEnabled.class)) {
-            pat.setAnnotatedType(new SafeguardAnnotatedTypeWrapper(pat.getAnnotatedType()));
+            pat.setAnnotatedType(new SafeguardAnnotatedTypeWrapper<>(pat.getAnnotatedType()));
         }
+        microProfileValidator.parse(pat.getAnnotatedType());
+    }
+
+    public void throwExceptions(@Observes AfterBeanDiscovery afterBeanDiscovery) {
+        microProfileValidator.forThrowable(afterBeanDiscovery::addDefinitionError);
     }
 
     private static class SafeguardAnnotatedTypeWrapper<X> implements AnnotatedType<X> {

http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
index e898875..41921c5 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
@@ -19,6 +19,7 @@
 
 package org.apache.safeguard.impl.executionPlans;
 
+import org.apache.safeguard.exception.SafeguardException;
 import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerBuilder;
 import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerDefinition;
 import org.apache.safeguard.impl.retry.FailsafeRetryBuilder;
@@ -30,6 +31,8 @@ import java.time.Duration;
 import java.util.concurrent.TimeoutException;
 
 class MicroprofileAnnotationMapper {
+    private static final String RETRY_FORMAT = "%s/Retry/%s";
+    private static final String CIRCUIT_BREAKER_FORMAT = "%s/CircuitBreaker/%s";
     static FailsafeRetryDefinition mapRetry(Retry retry, FailsafeRetryBuilder retryBuilder) {
         retryBuilder.withMaxRetries(retry.maxRetries())
                 .withRetryOn(retry.retryOn())

http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java
index 18bacf6..eb3c478 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java
@@ -19,6 +19,8 @@
 
 package org.apache.safeguard.impl.util;
 
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 
@@ -35,4 +37,14 @@ public final class AnnotationUtil {
             return method.getDeclaringClass().getAnnotation(clazz);
         }
     }
+
+    public static <T extends Annotation> T getAnnotation(AnnotatedMethod<?> method,
+                                                         AnnotatedType<?> type,
+                                                         Class<T> clazz) {
+        T annotation = method.getAnnotation(clazz);
+        if(annotation != null) {
+            return annotation;
+        }
+        return type.getAnnotation(clazz);
+    }
 }

http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/27626ffd/safeguard-tck-tests/pom.xml
----------------------------------------------------------------------
diff --git a/safeguard-tck-tests/pom.xml b/safeguard-tck-tests/pom.xml
index 1ec0c6b..580b8a3 100644
--- a/safeguard-tck-tests/pom.xml
+++ b/safeguard-tck-tests/pom.xml
@@ -72,23 +72,6 @@
                     </dependenciesToScan>
                     <excludes>
                         <exclude>org.eclipse.microprofile.fault.tolerance.tck.ConfigTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.illegalConfig.IncompatibleFallbackMethodTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.illegalConfig.IncompatibleFallbackMethodWithArgsTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.illegalConfig.IncompatibleFallbackTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidBulkheadAsynchQueueTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureRatioPosTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureReqVol0Test</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidRetryJitterTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureSuccess0Test</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerDelayTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidRetryDelayTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureRatioNegTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidBulkheadValueTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureReqVolNegTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidRetryDelayDurationTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidTimeoutValueTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidCircuitBreakerFailureSuccessNegTest</exclude>
-                        <exclude>org.eclipse.microprofile.fault.tolerance.tck.invalidParameters.InvalidRetryMaxRetriesTest</exclude>
                     </excludes>
                 </configuration>
             </plugin>