Creating the basic structure of the proposal sent by mail
diff --git a/README.md b/README.md
index e7ed37f..97588dd 100644
--- a/README.md
+++ b/README.md
@@ -76,4 +76,10 @@
}
-```
\ No newline at end of file
+```
+
+## Dev tip
+
+To find the interceptor priority you can use this shell command:
+
+`find . -name *Interceptor.java | xargs grep '@Priority' | sed 's/\([^:]*\):\(.*\)/\2 : \1/g' | sed 's/@Priority(Interceptor.Priority.PLATFORM_AFTER + \([0-9]*\))/priority = \1/' | sort`
diff --git a/pom.xml b/pom.xml
index 882c30f..f85ac1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,11 +29,12 @@
<artifactId>safeguard-parent</artifactId>
<version>1.1-SNAPSHOT</version>
<packaging>pom</packaging>
+ <name>Apache Safeguard</name>
+
<modules>
- <module>safeguard-api</module>
<module>safeguard-impl</module>
- <module>safeguard-tck-tests</module>
</modules>
+
<licenses>
<license>
<name>Apache License, Version 2.0</name>
@@ -72,30 +73,19 @@
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
- <microprofile-fault-tolerance.version>1.0</microprofile-fault-tolerance.version>
+ <microprofile-fault-tolerance.version>1.1.3</microprofile-fault-tolerance.version>
<owb.version>2.0.1</owb.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>
- <geronimo-config-impl.version>1.1</geronimo-config-impl.version>
+ <geronimo-config-impl.version>1.2</geronimo-config-impl.version>
<microprofile-config-api.version>1.2</microprofile-config-api.version>
- <failsafe.version>1.0.4</failsafe.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
- <groupId>org.apache.geronimo.safeguard</groupId>
- <artifactId>safeguard-api</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>net.jodah</groupId>
- <artifactId>failsafe</artifactId>
- <version>${failsafe.version}</version>
- </dependency>
- <dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
<version>1.0.1</version>
diff --git a/safeguard-api/pom.xml b/safeguard-api/pom.xml
deleted file mode 100644
index 8ba6b83..0000000
--- a/safeguard-api/pom.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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">
- <parent>
- <artifactId>safeguard-parent</artifactId>
- <groupId>org.apache.geronimo.safeguard</groupId>
- <version>1.1-SNAPSHOT</version>
- </parent>
- <name>Apache Safeguard :: API</name>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>safeguard-api</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jcdi_2.0_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-annotation_1.3_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-interceptor_1.2_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
- <artifactId>microprofile-fault-tolerance-api</artifactId>
- </dependency>
- </dependencies>
-</project>
\ No newline at end of file
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/ExecutionManager.java b/safeguard-api/src/main/java/org/apache/safeguard/api/ExecutionManager.java
deleted file mode 100644
index 1061043..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/ExecutionManager.java
+++ /dev/null
@@ -1,39 +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.safeguard.api;
-
-import org.apache.safeguard.api.bulkhead.BulkheadManager;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerManager;
-import org.apache.safeguard.api.retry.RetryManager;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public interface ExecutionManager {
- <T> T execute(String name, Callable<T> callable);
-
- Object execute(InvocationContext invocationContext);
-
- CircuitBreakerManager getCircuitBreakerManager();
-
- RetryManager getRetryManager();
-
- BulkheadManager getBulkheadManager();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/Bulkhead.java b/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/Bulkhead.java
deleted file mode 100644
index 5675a6d..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/Bulkhead.java
+++ /dev/null
@@ -1,32 +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.safeguard.api.bulkhead;
-
-import java.util.concurrent.Callable;
-
-public interface Bulkhead {
- BulkheadDefinition getBulkheadDefinition();
-
- int getCurrentQueueDepth();
-
- int getCurrentExecutions();
-
- <T> T execute(Callable<T> callable);
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadBuilder.java b/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadBuilder.java
deleted file mode 100644
index 19f7bdc..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadBuilder.java
+++ /dev/null
@@ -1,30 +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.safeguard.api.bulkhead;
-
-public interface BulkheadBuilder {
- BulkheadBuilder withMaxConcurrency(int maxConcurrency);
-
- BulkheadBuilder withMaxWaiting(int overflowCapacity);
-
- BulkheadBuilder asynchronous();
-
- BulkheadDefinition build();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadDefinition.java b/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadDefinition.java
deleted file mode 100644
index bb7e942..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadDefinition.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.safeguard.api.bulkhead;
-
-public interface BulkheadDefinition {
- int getMaxConcurrentExecutions();
-
- int getMaxWaitingExecutions();
-
- boolean isAsynchronous();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadManager.java b/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadManager.java
deleted file mode 100644
index 3b155ad..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/bulkhead/BulkheadManager.java
+++ /dev/null
@@ -1,25 +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.safeguard.api.bulkhead;
-
-public interface BulkheadManager {
- BulkheadBuilder newBulkheadBuilder(String name);
- Bulkhead getBulkhead(String name);
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreaker.java b/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreaker.java
deleted file mode 100644
index cce9b11..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreaker.java
+++ /dev/null
@@ -1,25 +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.safeguard.api.circuitbreaker;
-
-public interface CircuitBreaker {
- CircuitBreakerDefinition getDefinition();
- CircuitBreakerState getState();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerBuilder.java b/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerBuilder.java
deleted file mode 100644
index c20a426..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerBuilder.java
+++ /dev/null
@@ -1,36 +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.safeguard.api.circuitbreaker;
-
-import org.apache.safeguard.api.retry.RetryBuilder;
-import org.apache.safeguard.api.retry.RetryDefinition;
-
-import java.time.Duration;
-
-public interface CircuitBreakerBuilder {
- CircuitBreakerBuilder withDelay(Duration delay);
- CircuitBreakerBuilder withFailureCount(int failureCount);
- CircuitBreakerBuilder withFailures(int failureCount, int requestCount);
- CircuitBreakerBuilder withSuccessCount(int successCount);
- CircuitBreakerBuilder withSuccesses(int successCount, int requestCount);
- CircuitBreakerBuilder withFailOn(Class<? extends Throwable>... failOn);
-
- CircuitBreakerDefinition build();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerDefinition.java b/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerDefinition.java
deleted file mode 100644
index 7780ece..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerDefinition.java
+++ /dev/null
@@ -1,39 +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.safeguard.api.circuitbreaker;
-
-import javax.enterprise.util.Nonbinding;
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
-import java.util.Collection;
-
-public interface CircuitBreakerDefinition {
- Collection<Class<? extends Throwable>> getFailOn();
-
- Duration getDelay();
-
- int getRequestVolumeThreshold();
-
- double getFailureRatio();
-
- int getSuccessThreshold();
-
- double getSuccessRatio();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerManager.java b/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerManager.java
deleted file mode 100644
index 42028b1..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerManager.java
+++ /dev/null
@@ -1,25 +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.safeguard.api.circuitbreaker;
-
-public interface CircuitBreakerManager {
- CircuitBreakerBuilder newCircuitBreaker(String name);
- CircuitBreaker getCircuitBreaker(String name);
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/config/ConfigFacade.java b/safeguard-api/src/main/java/org/apache/safeguard/api/config/ConfigFacade.java
deleted file mode 100644
index a0af320..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/config/ConfigFacade.java
+++ /dev/null
@@ -1,61 +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.safeguard.api.config;
-
-import javax.annotation.Priority;
-import java.time.temporal.ChronoUnit;
-import java.util.Comparator;
-import java.util.ServiceLoader;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-public abstract class ConfigFacade {
- private static ConfigFacade INSTANCE;
-
- public abstract boolean getBoolean(String name, boolean defaultValue);
- public abstract long getLong(String name, long defaultValue);
- public abstract int getInt(String name, int defaultValue);
- public abstract double getDouble(String name, double defaultValue);
- public abstract ChronoUnit getChronoUnit(String name, ChronoUnit defaultValue);
- public abstract Class<? extends Throwable>[] getThrowableClasses(String name, Class<? extends Throwable>[] defaultValue);
-
- public static ConfigFacade getInstance() {
- if (INSTANCE == null) {
- INSTANCE = load();
- }
- return INSTANCE;
- }
-
- public static void setInstance(ConfigFacade configFacade) {
- INSTANCE = configFacade;
- }
-
- private static ConfigFacade load() {
- ServiceLoader<ConfigFacade> configFacades = ServiceLoader.load(ConfigFacade.class);
- SortedSet<ConfigFacade> configFacedSet = new TreeSet<>(Comparator.comparingInt(c -> {
- Priority p = c.getClass().getAnnotation(Priority.class);
- return p == null ? 1 : p.value();
- }));
- for(ConfigFacade facade : configFacades) {
- configFacedSet.add(facade);
- }
- return configFacedSet.first();
- }
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryBuilder.java b/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryBuilder.java
deleted file mode 100644
index 10228db..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryBuilder.java
+++ /dev/null
@@ -1,34 +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.safeguard.api.retry;
-
-import java.time.Duration;
-
-public interface RetryBuilder {
-
- RetryBuilder withMaxRetries(int maxRetries);
- RetryBuilder withDelay(Duration delay);
- RetryBuilder withMaxDuration(Duration maxDuration);
- RetryBuilder withJitter(Duration jitter);
- RetryBuilder withAbortOn(Class<? extends Throwable>... abortOn);
- RetryBuilder withRetryOn(Class<? extends Throwable>... retryOn);
-
- RetryDefinition build();
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryDefinition.java b/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryDefinition.java
deleted file mode 100644
index 1383e17..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryDefinition.java
+++ /dev/null
@@ -1,39 +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.safeguard.api.retry;
-
-import java.time.Duration;
-import java.util.Collection;
-
-public interface RetryDefinition {
-
- int getMaxRetries();
-
- Duration getDelay();
-
- Duration getMaxDuration();
-
- Duration getJitter();
-
- Collection<Class<? extends Throwable>> getRetryExceptions();
-
- Collection<Class<? extends Throwable>> getAbortExceptions();
-
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryManager.java b/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryManager.java
deleted file mode 100644
index 054d8d8..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/retry/RetryManager.java
+++ /dev/null
@@ -1,25 +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.safeguard.api.retry;
-
-public interface RetryManager {
- RetryBuilder newRetryDefinition(String name);
- RetryDefinition getRetryDefinition(String name);
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/exception/AsyncException.java b/safeguard-api/src/main/java/org/apache/safeguard/exception/AsyncException.java
deleted file mode 100644
index f21cf28..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/exception/AsyncException.java
+++ /dev/null
@@ -1,26 +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.safeguard.exception;
-
-public class AsyncException extends SafeguardException {
- public AsyncException(Exception e) {
- super(e);
- }
-}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/exception/SafeguardException.java b/safeguard-api/src/main/java/org/apache/safeguard/exception/SafeguardException.java
deleted file mode 100644
index a8991e1..0000000
--- a/safeguard-api/src/main/java/org/apache/safeguard/exception/SafeguardException.java
+++ /dev/null
@@ -1,40 +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.safeguard.exception;
-
-import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceException;
-
-public class SafeguardException extends FaultToleranceException{
- public SafeguardException() {
- }
-
- public SafeguardException(String message) {
- super(message);
- }
-
- public SafeguardException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public SafeguardException(Throwable cause) {
- super(cause);
- }
-
-}
diff --git a/safeguard-impl/pom.xml b/safeguard-impl/pom.xml
index f011417..9022b62 100644
--- a/safeguard-impl/pom.xml
+++ b/safeguard-impl/pom.xml
@@ -24,20 +24,26 @@
<groupId>org.apache.geronimo.safeguard</groupId>
<version>1.1-SNAPSHOT</version>
</parent>
- <name>Apache Safeguard :: Implementation (Failsafe)</name>
+
<modelVersion>4.0.0</modelVersion>
<artifactId>safeguard-impl</artifactId>
+ <name>Apache Safeguard :: Implementation</name>
<dependencies>
<dependency>
- <groupId>org.apache.geronimo.safeguard</groupId>
- <artifactId>safeguard-api</artifactId>
+ <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+ <artifactId>microprofile-fault-tolerance-api</artifactId>
+ <version>${microprofile-fault-tolerance.version}</version>
+ <scope>provided</scope>
</dependency>
<dependency>
- <groupId>net.jodah</groupId>
- <artifactId>failsafe</artifactId>
+ <groupId>org.eclipse.microprofile.metrics</groupId>
+ <artifactId>microprofile-metrics-api</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
</dependency>
+
<dependency>
<groupId>org.jboss.arquillian.testng</groupId>
<artifactId>arquillian-testng-container</artifactId>
@@ -74,5 +80,34 @@
<groupId>org.apache.geronimo.config</groupId>
<artifactId>geronimo-config-impl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
+ <artifactId>microprofile-fault-tolerance-tck</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo</groupId>
+ <artifactId>geronimo-metrics</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>3.0.0-M1</version>
+ <configuration>
+ <dependenciesToScan>
+ <dependency>org.eclipse.microprofile.fault-tolerance:microprofile-fault-tolerance-tck</dependency>
+ </dependenciesToScan>
+ <excludes>
+ <exclude>org.eclipse.microprofile.fault.tolerance.tck.ConfigTest</exclude>
+ </excludes>
+ <trimStackTrace>false</trimStackTrace>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
\ No newline at end of file
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java
deleted file mode 100644
index db57b3f..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java
+++ /dev/null
@@ -1,111 +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.safeguard.impl;
-
-import org.apache.safeguard.api.ExecutionManager;
-import org.apache.safeguard.api.bulkhead.BulkheadManager;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerManager;
-import org.apache.safeguard.api.retry.RetryManager;
-import org.apache.safeguard.impl.bulkhead.BulkheadManagerImpl;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerManager;
-import org.apache.safeguard.impl.config.MicroprofileAnnotationMapper;
-import org.apache.safeguard.impl.executionPlans.ExecutionPlanFactory;
-import org.apache.safeguard.impl.executorService.DefaultExecutorServiceProvider;
-import org.apache.safeguard.impl.executorService.ExecutorServiceProvider;
-import org.apache.safeguard.impl.retry.FailsafeRetryManager;
-
-import javax.enterprise.inject.Vetoed;
-import javax.interceptor.InvocationContext;
-import java.lang.reflect.Method;
-import java.time.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-
-@Vetoed
-public class FailsafeExecutionManager implements ExecutionManager {
- private final MicroprofileAnnotationMapper mapper;
- private final BulkheadManager bulkheadManager;
- private final CircuitBreakerManager circuitBreakerManager;
- private final RetryManager retryManager;
- private final ExecutionPlanFactory executionPlanFactory;
- private final ExecutorServiceProvider executorServiceProvider;
-
- public FailsafeExecutionManager() {
- FailsafeCircuitBreakerManager circuitBreakerManager = new FailsafeCircuitBreakerManager();
- FailsafeRetryManager retryManager = new FailsafeRetryManager();
- BulkheadManagerImpl bulkheadManager = new BulkheadManagerImpl();
- this.mapper = MicroprofileAnnotationMapper.getInstance();
- this.executorServiceProvider = new DefaultExecutorServiceProvider(Executors.newScheduledThreadPool(5));
- this.executionPlanFactory = new ExecutionPlanFactory(circuitBreakerManager, retryManager, bulkheadManager, mapper,
- executorServiceProvider);
- this.circuitBreakerManager = circuitBreakerManager;
- this.retryManager = retryManager;
- this.bulkheadManager = bulkheadManager;
- }
-
- public FailsafeExecutionManager(MicroprofileAnnotationMapper mapper, BulkheadManagerImpl bulkheadManager,
- FailsafeCircuitBreakerManager circuitBreakerManager, FailsafeRetryManager retryManager,
- ExecutionPlanFactory executionPlanFactory, ExecutorServiceProvider executorServiceProvider) {
- this.mapper = mapper;
- this.bulkheadManager = bulkheadManager;
- this.circuitBreakerManager = circuitBreakerManager;
- this.retryManager = retryManager;
- this.executionPlanFactory = executionPlanFactory;
- this.executorServiceProvider = executorServiceProvider;
- }
-
- public Object execute(InvocationContext invocationContext) {
- Method method = invocationContext.getMethod();
- return executionPlanFactory.locateExecutionPlan(method).execute(invocationContext::proceed, invocationContext);
- }
-
- @Override
- public <T> T execute(String name, Callable<T> callable) {
- return executionPlanFactory.locateExecutionPlan(name, null, false).execute(callable, null);
- }
-
- public <T> T executeAsync(String name, Callable<T> callable) {
- return executionPlanFactory.locateExecutionPlan(name, null, true).execute(callable, null);
- }
-
- public <T> T executeAsync(String name, Callable<T> callable, Duration timeout) {
- return executionPlanFactory.locateExecutionPlan(name, timeout, true).execute(callable, null);
- }
-
- public ExecutionPlanFactory getExecutionPlanFactory() {
- return executionPlanFactory;
- }
-
- @Override
- public CircuitBreakerManager getCircuitBreakerManager() {
- return circuitBreakerManager;
- }
-
- @Override
- public RetryManager getRetryManager() {
- return retryManager;
- }
-
- @Override
- public BulkheadManager getBulkheadManager() {
- return bulkheadManager;
- }
-
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/annotation/AnnotationFinder.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/annotation/AnnotationFinder.java
new file mode 100644
index 0000000..9fe2f28
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/annotation/AnnotationFinder.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.safeguard.impl.annotation;
+
+import static java.util.Optional.ofNullable;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.InvocationContext;
+
+@ApplicationScoped
+public class AnnotationFinder {
+ @Inject
+ private BeanManager manager;
+
+ public <T extends Annotation> T findAnnotation(final Class<T> type, final InvocationContext context) {
+ Class<?> target = context.getTarget().getClass();
+ while (target.getName().contains("$$")) {
+ target = target.getSuperclass();
+ }
+ return manager.createAnnotatedType(target).getMethods().stream()
+ .filter(it -> it.getJavaMember().getName().equals(context.getMethod().getName()) &&
+ Arrays.equals(it.getJavaMember().getParameterTypes(), context.getMethod().getParameterTypes()))
+ .findFirst()
+ .map(m -> m.getAnnotation(type))
+ .orElseGet(() -> ofNullable(context.getMethod().getAnnotation(type))
+ .orElseGet(() -> context.getTarget().getClass().getAnnotation(type)));
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/AsynchronousInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/AsynchronousInterceptor.java
new file mode 100644
index 0000000..fa375f2
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/AsynchronousInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.safeguard.impl.asynchronous;
+
+import java.util.concurrent.Executor;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.customizable.Safeguard;
+import org.eclipse.microprofile.faulttolerance.Asynchronous;
+
+@Interceptor
+@Asynchronous
+@Priority(Interceptor.Priority.PLATFORM_AFTER + 1)
+public class AsynchronousInterceptor extends BaseAsynchronousInterceptor {
+ @Inject
+ @Safeguard
+ private Executor executor;
+
+ @Override
+ protected Executor getExecutor(final InvocationContext context) {
+ return executor;
+ }
+
+ @AroundInvoke
+ public Object async(final InvocationContext context) throws Exception {
+ return around(context);
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java
new file mode 100644
index 0000000..db68832
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/asynchronous/BaseAsynchronousInterceptor.java
@@ -0,0 +1,129 @@
+/*
+ * 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.asynchronous;
+
+import java.io.Serializable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+
+import org.eclipse.microprofile.faulttolerance.Asynchronous;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
+
+public abstract class BaseAsynchronousInterceptor implements Serializable {
+ protected abstract Executor getExecutor(InvocationContext context);
+
+ protected Object around(final InvocationContext context) throws Exception {
+ if (context.getContextData().get(Asynchronous.class.getName()) != null) { // bulkhead or so handling threading
+ return context.proceed();
+ }
+
+ context.getContextData().put(Asynchronous.class.getName(), "true");
+
+ final Class<?> returnType = context.getMethod().getReturnType();
+ if (CompletionStage.class.isAssignableFrom(returnType)) {
+ final CompletableFuture future = new CompletableFuture<>();
+ getExecutor(context).execute(() -> {
+ try {
+ final Object proceed = context.proceed();
+ final CompletionStage<?> stage = CompletionStage.class.cast(proceed);
+ stage.handle((r, e) -> {
+ if (e != null) {
+ future.completeExceptionally(e);
+ } else {
+ future.complete(r);
+ }
+ return null;
+ });
+ } catch (final Exception e) {
+ future.completeExceptionally(e);
+ }
+ });
+ return future;
+ }
+ if (Future.class.isAssignableFrom(returnType)) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicReference<Future<?>> ref = new AtomicReference<>();
+ getExecutor(context).execute(() -> {
+ final Object proceed;
+ try {
+ proceed = context.proceed();
+ ref.set(Future.class.cast(proceed));
+ } catch (final Exception e) {
+ final CompletableFuture<Object> failingFuture = new CompletableFuture<>();
+ failingFuture.completeExceptionally(e);
+ ref.set(failingFuture);
+ } finally {
+ latch.countDown();
+ }
+ });
+ return new Future() {
+ private void await() {
+ try {
+ latch.await();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ await();
+ return ref.get().cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ await();
+ return ref.get().isCancelled();
+ }
+
+ @Override
+ public boolean isDone() {
+ await();
+ return ref.get().isDone();
+ }
+
+ @Override
+ public Object get() throws InterruptedException, ExecutionException {
+ await();
+ return ref.get().get();
+ }
+
+ @Override
+ public Object get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ await();
+ return ref.get().get(timeout, unit);
+ }
+ };
+ }
+ throw new FaultToleranceDefinitionException(
+ "Unsupported return type: " + returnType + " (from: " + context.getMethod() + ")." +
+ "Should be Future or CompletionStage.");
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadBuilderImpl.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadBuilderImpl.java
deleted file mode 100644
index 825c576..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadBuilderImpl.java
+++ /dev/null
@@ -1,62 +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.safeguard.impl.bulkhead;
-
-import org.apache.safeguard.api.bulkhead.BulkheadBuilder;
-import org.apache.safeguard.api.bulkhead.BulkheadDefinition;
-
-public class BulkheadBuilderImpl implements BulkheadBuilder{
- private final String name;
- private final BulkheadManagerImpl bulkheadManager;
- private int maxWaitingExecutions;
- private int maxConcurrentExecutions;
- private boolean asynchronous = false;
-
- BulkheadBuilderImpl(String name, BulkheadManagerImpl bulkheadManager) {
- this.name = name;
- this.bulkheadManager = bulkheadManager;
- }
-
- @Override
- public BulkheadBuilder withMaxConcurrency(int maxConcurrency) {
- this.maxConcurrentExecutions = maxConcurrency;
- return this;
- }
-
- @Override
- public BulkheadBuilder withMaxWaiting(int overflowCapacity) {
- this.maxWaitingExecutions = overflowCapacity;
- return this;
- }
-
- @Override
- public BulkheadBuilder asynchronous() {
- this.asynchronous = true;
- return this;
- }
-
- @Override
- public BulkheadDefinition build() {
- BulkheadDefinitionImpl definition = new BulkheadDefinitionImpl(maxConcurrentExecutions, maxWaitingExecutions, asynchronous);
- bulkheadManager.register(name, definition);
- return definition;
-
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadDefinitionImpl.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadDefinitionImpl.java
deleted file mode 100644
index 7c30c13..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadDefinitionImpl.java
+++ /dev/null
@@ -1,49 +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.safeguard.impl.bulkhead;
-
-import org.apache.safeguard.api.bulkhead.BulkheadDefinition;
-
-public class BulkheadDefinitionImpl implements BulkheadDefinition{
- private final int maxConcurrentExecutions;
- private final int maxWaitingExecutions;
- private final boolean asynchronous;
-
- public BulkheadDefinitionImpl(int maxConcurrentExecutions, int maxWaitingExecutions, boolean asynchronous) {
- this.maxConcurrentExecutions = maxConcurrentExecutions;
- this.maxWaitingExecutions = maxWaitingExecutions;
- this.asynchronous = asynchronous;
- }
-
- @Override
- public int getMaxConcurrentExecutions() {
- return maxConcurrentExecutions;
- }
-
- @Override
- public int getMaxWaitingExecutions() {
- return maxWaitingExecutions;
- }
-
- @Override
- public boolean isAsynchronous() {
- return asynchronous;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java
new file mode 100644
index 0000000..6bdb6f7
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadInterceptor.java
@@ -0,0 +1,131 @@
+/*
+ * 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.bulkhead;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.annotation.AnnotationFinder;
+import org.apache.safeguard.impl.asynchronous.BaseAsynchronousInterceptor;
+import org.eclipse.microprofile.faulttolerance.Asynchronous;
+import org.eclipse.microprofile.faulttolerance.Bulkhead;
+import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
+
+@Bulkhead
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER + 5)
+public class BulkheadInterceptor extends BaseAsynchronousInterceptor {
+ private static final String EXECUTOR_KEY = BulkheadInterceptor.class.getName() + ".executor";
+
+ @Inject
+ private Cache cache;
+
+ @AroundInvoke
+ public Object bulkhead(final InvocationContext context) throws Exception {
+ final Map<Method, Model> models = cache.getModels();
+ Model model = models.get(context.getMethod());
+ if (model == null) {
+ model = cache.create(context);
+ final Model existing = models.putIfAbsent(context.getMethod(), model);
+ if (existing != null) {
+ model = existing;
+ }
+ }
+ if (model.useThreads) {
+ context.getContextData().put(EXECUTOR_KEY, model.pool);
+ return around(context);
+ } else {
+ if (!model.semaphore.tryAcquire()) {
+ throw new BulkheadException("No more permission available");
+ }
+ try {
+ return context.proceed();
+ } finally {
+ model.semaphore.release();
+ }
+ }
+ }
+
+ @Override
+ protected Executor getExecutor(final InvocationContext context) {
+ return Executor.class.cast(context.getContextData().get(EXECUTOR_KEY));
+ }
+
+ static class Model {
+ private final int value;
+ private final int waitingQueue;
+ private final boolean useThreads;
+ private final ExecutorService pool;
+ private final Semaphore semaphore;
+
+ private Model(final Bulkhead bulkhead, final boolean useThreads) {
+ this.value = bulkhead.value();
+ if (this.value <= 0) {
+ throw new FaultToleranceDefinitionException("Invalid value in @Bulkhead: " + value);
+ }
+
+ this.waitingQueue = bulkhead.waitingTaskQueue();
+ if (this.waitingQueue <= 0) {
+ throw new FaultToleranceDefinitionException("Invalid value in @Bulkhead: " + value);
+ }
+
+ this.useThreads = useThreads;
+ if (this.useThreads) {
+ this.pool = new ThreadPoolExecutor(value, value, 0L, MILLISECONDS, new ArrayBlockingQueue<>(waitingQueue));
+ this.semaphore = null;
+ } else {
+ this.pool = null;
+ this.semaphore = new Semaphore(value);
+ }
+ }
+ }
+
+ @ApplicationScoped
+ public static class Cache {
+ private final Map<Method, Model> models = new ConcurrentHashMap<>();
+
+ @Inject
+ private AnnotationFinder finder;
+
+ public Map<Method, Model> getModels() {
+ return models;
+ }
+
+ public Model create(final InvocationContext context) {
+ return new Model(finder.findAnnotation(Bulkhead.class, context),
+ finder.findAnnotation(Asynchronous.class, context) != null);
+ }
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadManagerImpl.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadManagerImpl.java
deleted file mode 100644
index 9794bd7..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/BulkheadManagerImpl.java
+++ /dev/null
@@ -1,51 +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.safeguard.impl.bulkhead;
-
-import org.apache.safeguard.api.bulkhead.Bulkhead;
-import org.apache.safeguard.api.bulkhead.BulkheadBuilder;
-import org.apache.safeguard.api.bulkhead.BulkheadManager;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class BulkheadManagerImpl implements BulkheadManager{
- private Map<String, Bulkhead> bulkheads = new HashMap<>();;
- @Override
- public BulkheadBuilder newBulkheadBuilder(String name) {
- return new BulkheadBuilderImpl(name, this);
- }
-
- @Override
- public Bulkhead getBulkhead(String name) {
- return bulkheads.get(name);
- }
-
- void register(String name, BulkheadDefinitionImpl bulkheadDefinition) {
- Bulkhead bulkhead;
- if (bulkheadDefinition.isAsynchronous()) {
- bulkhead = new ThreadPoolBulkhead(bulkheadDefinition);
- }
- else {
- bulkhead = new SemaphoreBulkhead(bulkheadDefinition);
- }
- bulkheads.put(name, bulkhead);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/SemaphoreBulkhead.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/SemaphoreBulkhead.java
deleted file mode 100644
index 83c940c..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/SemaphoreBulkhead.java
+++ /dev/null
@@ -1,65 +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.safeguard.impl.bulkhead;
-
-import org.apache.safeguard.api.bulkhead.Bulkhead;
-import org.apache.safeguard.api.bulkhead.BulkheadDefinition;
-import org.apache.safeguard.exception.SafeguardException;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.Semaphore;
-
-public class SemaphoreBulkhead implements Bulkhead {
- private final Semaphore semaphore;
- private final BulkheadDefinition bulkheadDefinition;
-
- public SemaphoreBulkhead(BulkheadDefinition bulkheadDefinition) {
- this.semaphore = new Semaphore(bulkheadDefinition.getMaxConcurrentExecutions(), true);
- this.bulkheadDefinition = bulkheadDefinition;
- }
-
- @Override
- public BulkheadDefinition getBulkheadDefinition() {
- return this.bulkheadDefinition;
- }
-
- @Override
- public int getCurrentQueueDepth() {
- return semaphore.getQueueLength();
- }
-
- @Override
- public int getCurrentExecutions() {
- return bulkheadDefinition.getMaxConcurrentExecutions() - semaphore.availablePermits();
- }
-
- @Override
- public <T> T execute(Callable<T> callable) {
- try {
- String name = Thread.currentThread().getName();
- this.semaphore.acquire();
- return callable.call();
- } catch (Exception e) {
- throw new SafeguardException(e);
- } finally {
- this.semaphore.release();
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/ThreadPoolBulkhead.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/ThreadPoolBulkhead.java
deleted file mode 100644
index 1372175..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/bulkhead/ThreadPoolBulkhead.java
+++ /dev/null
@@ -1,110 +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.safeguard.impl.bulkhead;
-
-import org.apache.safeguard.api.bulkhead.Bulkhead;
-import org.apache.safeguard.api.bulkhead.BulkheadDefinition;
-import org.eclipse.microprofile.faulttolerance.exceptions.BulkheadException;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-public class ThreadPoolBulkhead implements Bulkhead {
- private final BulkheadDefinition bulkheadDefinition;
- private final BlockingQueue<Runnable> workQueue;
- private final ThreadPoolExecutor threadPoolExecutor;
-
- public ThreadPoolBulkhead(BulkheadDefinition bulkheadDefinition) {
- this.bulkheadDefinition = bulkheadDefinition;
- this.workQueue = new LinkedBlockingQueue<>(bulkheadDefinition.getMaxWaitingExecutions());
- this.threadPoolExecutor = new ThreadPoolExecutor(
- bulkheadDefinition.getMaxConcurrentExecutions(),
- bulkheadDefinition.getMaxConcurrentExecutions(),
- 0L, TimeUnit.MILLISECONDS,
- workQueue,
- Executors.defaultThreadFactory());
- }
-
- @Override
- public BulkheadDefinition getBulkheadDefinition() {
- return bulkheadDefinition;
- }
-
- @Override
- public int getCurrentQueueDepth() {
- return workQueue.size();
- }
-
- @Override
- public int getCurrentExecutions() {
- return threadPoolExecutor.getActiveCount();
- }
-
- @Override
- public <T> T execute(Callable<T> callable) {
- try {
- return (T)new DelegatingFuture<T>((Future<Future<T>>) threadPoolExecutor.submit(callable));
- } catch (RejectedExecutionException e) {
- throw new BulkheadException(e);
- }
- }
-
- private class DelegatingFuture<R> implements Future<R>{
-
- private final Future<Future<R>> child;
-
- public DelegatingFuture(Future<Future<R>> child) {
- this.child = child;
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- return child.cancel(mayInterruptIfRunning);
- }
-
- @Override
- public boolean isCancelled() {
- return child.isCancelled();
- }
-
- @Override
- public boolean isDone() {
- return child.isDone();
- }
-
- @Override
- public R get() throws InterruptedException, ExecutionException {
- return child.get().get();
- }
-
- @Override
- public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- return child.get().get(timeout, unit);
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FailsafeExecutionManagerProvider.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FallbackBinding.java
similarity index 66%
rename from safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FailsafeExecutionManagerProvider.java
rename to safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FallbackBinding.java
index 37d1cab..dcf579b 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FailsafeExecutionManagerProvider.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/FallbackBinding.java
@@ -16,20 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.safeguard.impl.cdi;
-import org.apache.safeguard.api.ExecutionManager;
-import org.apache.safeguard.impl.FailsafeExecutionManager;
+import javax.enterprise.util.AnnotationLiteral;
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Produces;
+import org.eclipse.microprofile.faulttolerance.Fallback;
+import org.eclipse.microprofile.faulttolerance.FallbackHandler;
-@ApplicationScoped
-public class FailsafeExecutionManagerProvider {
- @Produces
- @ApplicationScoped
- public ExecutionManager createExecutionManager() {
- return new FailsafeExecutionManager();
+public class FallbackBinding extends AnnotationLiteral<Fallback> implements Fallback {
+ @Override
+ public Class<? extends FallbackHandler<?>> value() {
+ return DEFAULT.class;
+ }
+
+ @Override
+ public String fallbackMethod() {
+ return "";
}
}
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
deleted file mode 100644
index 714818b..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/MicroProfileValidator.java
+++ /dev/null
@@ -1,143 +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.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);
- }
-}
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 0bd2e9d..e16294b 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
@@ -1,118 +1,72 @@
-/*
- * 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.api.SafeguardEnabled;
-import org.eclipse.microprofile.faulttolerance.Bulkhead;
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Retry;
-import org.eclipse.microprofile.faulttolerance.Timeout;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
-import javax.enterprise.inject.spi.AnnotatedConstructor;
-import javax.enterprise.inject.spi.AnnotatedField;
-import javax.enterprise.inject.spi.AnnotatedMethod;
-import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
-import javax.enterprise.inject.spi.WithAnnotations;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
+import javax.enterprise.inject.spi.ProcessBean;
-import static org.apache.safeguard.api.SafeguardEnabled.INSTANCE;
+import org.apache.safeguard.impl.config.GeronimoFaultToleranceConfig;
+import org.apache.safeguard.impl.customizable.Safeguard;
+import org.apache.safeguard.impl.fallback.FallbackInterceptor;
+// todo: mp.fault.tolerance.interceptor.priority handling
public class SafeguardExtension implements Extension {
- 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()));
- }
- microProfileValidator.parse(pat.getAnnotatedType());
+ private boolean foundExecutor;
+
+ void addFallbackInterceptor(@Observes final ProcessAnnotatedType<FallbackInterceptor> processAnnotatedType) {
+ processAnnotatedType.configureAnnotatedType().add(new FallbackBinding());
}
- public void throwExceptions(@Observes AfterBeanDiscovery afterBeanDiscovery) {
- microProfileValidator.forThrowable(afterBeanDiscovery::addDefinitionError);
+ void onBean(@Observes final ProcessBean<?> bean) {
+ if (bean.getBean().getQualifiers().stream().anyMatch(it -> it.annotationType() == Safeguard.class)
+ && bean.getBean().getTypes().stream().anyMatch(it -> Executor.class.isAssignableFrom(toClass(it)))) {
+ foundExecutor = true;
+ }
}
- private static class SafeguardAnnotatedTypeWrapper<X> implements AnnotatedType<X> {
+ void addMissingBeans(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
+ final GeronimoFaultToleranceConfig config = GeronimoFaultToleranceConfig.create();
+ afterBeanDiscovery.addBean()
+ .id("geronimo_safeguard#configuration")
+ .types(GeronimoFaultToleranceConfig.class, Object.class)
+ .beanClass(GeronimoFaultToleranceConfig.class)
+ .qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
+ .createWith(c -> config);
- private final AnnotatedType<X> delegate;
- private final Set<Annotation> annotations;
-
- private SafeguardAnnotatedTypeWrapper(AnnotatedType<X> delegate) {
- this.delegate = delegate;
- Set<Annotation> annotations = delegate.getAnnotations();
- Set<Annotation> allAnotations = new LinkedHashSet<>();
- allAnotations.add(INSTANCE);
- allAnotations.addAll(annotations);
- this.annotations = allAnotations;
+ if (!foundExecutor) {
+ afterBeanDiscovery.addBean()
+ .id("geronimo_safeguard#executor")
+ .types(Executor.class, Object.class)
+ .beanClass(Executor.class)
+ .qualifiers(Safeguard.Literal.INSTANCE, Any.Literal.INSTANCE)
+ .createWith(c -> Executors.newCachedThreadPool())
+ .destroyWith((e, c) -> ExecutorService.class.cast(e).shutdownNow());
}
+ }
- @Override
- public Class<X> getJavaClass() {
- return delegate.getJavaClass();
- }
+ public Class<?> toClass(final Type it) {
+ return doToClass(it, 0);
+ }
- @Override
- public Set<AnnotatedConstructor<X>> getConstructors() {
- return delegate.getConstructors();
+ private Class<?> doToClass(final Type it, final int iterations) {
+ if (Class.class.isInstance(it)) {
+ return Class.class.cast(it);
}
-
- @Override
- public Set<AnnotatedMethod<? super X>> getMethods() {
- return delegate.getMethods();
+ if (iterations > 100) { // with generic it happens we can loop here
+ return Object.class;
}
-
- @Override
- public Set<AnnotatedField<? super X>> getFields() {
- return delegate.getFields();
+ if (ParameterizedType.class.isInstance(it)) {
+ return doToClass(ParameterizedType.class.cast(it).getRawType(), iterations + 1);
}
-
- @Override
- public Type getBaseType() {
- return delegate.getBaseType();
- }
-
- @Override
- public Set<Type> getTypeClosure() {
- return delegate.getTypeClosure();
- }
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
- return SafeguardEnabled.class.equals(annotationType) ? (T) INSTANCE : delegate.getAnnotation(annotationType);
- }
-
- @Override
- public Set<Annotation> getAnnotations() {
- return Collections.unmodifiableSet(annotations);
- }
-
- @Override
- public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
- return SafeguardEnabled.class.equals(annotationType) || delegate.isAnnotationPresent(annotationType);
- }
+ return Object.class; // will not match any of our test
}
}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardInterceptor.java
deleted file mode 100644
index 1c211b5..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/cdi/SafeguardInterceptor.java
+++ /dev/null
@@ -1,65 +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.safeguard.impl.cdi;
-
-import org.apache.safeguard.api.ExecutionManager;
-import org.apache.safeguard.api.SafeguardEnabled;
-import org.apache.safeguard.impl.FailsafeExecutionManager;
-import org.apache.safeguard.impl.util.AnnotationUtil;
-import org.eclipse.microprofile.faulttolerance.Bulkhead;
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Fallback;
-import org.eclipse.microprofile.faulttolerance.Retry;
-import org.eclipse.microprofile.faulttolerance.Timeout;
-
-import javax.annotation.Priority;
-import javax.enterprise.context.Dependent;
-import javax.inject.Inject;
-import javax.interceptor.AroundInvoke;
-import javax.interceptor.Interceptor;
-import javax.interceptor.InvocationContext;
-import java.lang.reflect.Method;
-
-@Interceptor
-@SafeguardEnabled
-@Priority(400)
-@Dependent
-public class SafeguardInterceptor {
- @Inject
- private ExecutionManager executionManager;
-
- @AroundInvoke
- public Object runSafeguards(InvocationContext invocationContext) throws Exception{
- if(isMethodSafeguarded(invocationContext.getMethod())) {
- return executionManager.execute(invocationContext);
- }
- else {
- return invocationContext.proceed();
- }
- }
-
- private boolean isMethodSafeguarded(Method method) {
- return AnnotationUtil.getAnnotation(method, Retry.class) != null ||
- AnnotationUtil.getAnnotation(method, CircuitBreaker.class) != null ||
- AnnotationUtil.getAnnotation(method, Timeout.class) != null ||
- AnnotationUtil.getAnnotation(method, Fallback.class) != null ||
- AnnotationUtil.getAnnotation(method, Bulkhead.class) != null;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java
new file mode 100644
index 0000000..eecb8e3
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/CircuitBreakerInterceptor.java
@@ -0,0 +1,291 @@
+/*
+ * 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.circuitbreaker;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Stream;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.annotation.AnnotationFinder;
+import org.apache.safeguard.impl.config.ConfigurationMapper;
+import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
+import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
+
+@CircuitBreaker
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER + 2)
+public class CircuitBreakerInterceptor implements Serializable {
+ @Inject
+ private Cache cache;
+
+ @AroundInvoke
+ public Object ifNotOpen(final InvocationContext context) throws Exception {
+ final Map<Method, CircuitBreakerImpl> circuitBreakers = cache.getCircuitBreakers();
+ CircuitBreakerImpl circuitBreaker = circuitBreakers.get(context.getMethod());
+ if (circuitBreaker == null) {
+ circuitBreaker = cache.create(context);
+ final CircuitBreakerImpl existing = circuitBreakers.putIfAbsent(context.getMethod(), circuitBreaker);
+ if (existing != null) {
+ circuitBreaker = existing;
+ }
+ }
+ if (!circuitBreaker.checkState()) {
+ throw new CircuitBreakerOpenException(context.getMethod() + " circuit breaker is open");
+ }
+ try {
+ return context.proceed();
+ } catch (final Exception e) {
+ if (circuitBreaker.failOn.length > 0 &&
+ Stream.of(circuitBreaker.failOn).anyMatch(it -> it.isInstance(e) || it.isInstance(e.getCause()))) {
+ circuitBreaker.incrementAndCheckState(1);
+ }
+ throw e;
+ }
+ }
+
+ private enum State {
+ CLOSED {
+ @Override
+ public State oppositeState() {
+ return OPEN;
+ }
+ },
+
+ OPEN {
+ @Override
+ public State oppositeState() {
+ return CLOSED;
+ }
+ };
+
+ /**
+ * Returns the opposite state to the represented state. This is useful
+ * for flipping the current state.
+ *
+ * @return the opposite state
+ */
+ public abstract State oppositeState();
+ }
+
+ @ApplicationScoped
+ public static class Cache {
+ private final Map<Method, CircuitBreakerImpl> circuitBreakers = new ConcurrentHashMap<>();
+
+ @Inject
+ private AnnotationFinder finder;
+
+ @Inject
+ private ConfigurationMapper mapper;
+
+ public Map<Method, CircuitBreakerImpl> getCircuitBreakers() {
+ return circuitBreakers;
+ }
+
+ public CircuitBreakerImpl create(final InvocationContext context) {
+ final CircuitBreaker definition = mapper.map(
+ finder.findAnnotation(CircuitBreaker.class, context), context.getMethod(), CircuitBreaker.class);
+ final long delay = definition.delayUnit().getDuration().toNanos() * definition.delay();
+ if (delay < 0) {
+ throw new FaultToleranceDefinitionException("CircuitBreaker delay can't be < 0");
+ }
+
+ final Class<? extends Throwable>[] failOn = definition.failOn();
+
+ final double failureRatio = definition.failureRatio();
+ if (failureRatio < 0) {
+ throw new FaultToleranceDefinitionException("CircuitBreaker failure ratio can't be < 0");
+ }
+
+ final int volumeThreshold = definition.requestVolumeThreshold();
+ if (volumeThreshold < 1) {
+ throw new FaultToleranceDefinitionException("CircuitBreaker volume threshold can't be < 0");
+ }
+
+ final int successThreshold = definition.successThreshold();
+ if (successThreshold < 0) {
+ throw new FaultToleranceDefinitionException("CircuitBreaker success threshold can't be < 0");
+ }
+ return new CircuitBreakerImpl(volumeThreshold, delay, successThreshold, delay, failOn, failureRatio);
+ }
+ }
+
+ // from commons-lang - todo: refine
+ public static class CircuitBreakerImpl {
+ private static final Map<State, StateStrategy> STRATEGY_MAP = createStrategyMap();
+
+ private final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
+ private final AtomicReference<CheckIntervalData> checkIntervalData;
+ private final int openingThreshold;
+ private final long openingInterval;
+ private final int closingThreshold;
+ private final long closingInterval;
+ private final double failureRatio;
+ private final Class<? extends Throwable>[] failOn;
+
+ private CircuitBreakerImpl(final int openingThreshold, final long openingInterval,
+ final int closingThreshold, final long closingInterval,
+ final Class<? extends Throwable>[] failOn,
+ final double failureRatio) {
+ this.checkIntervalData = new AtomicReference<>(new CheckIntervalData(0, 0));
+ this.openingThreshold = openingThreshold;
+ this.openingInterval = openingInterval;
+ this.closingThreshold = closingThreshold;
+ this.closingInterval = closingInterval;
+ this.failOn = failOn;
+ this.failureRatio = failureRatio;
+ }
+
+ protected static boolean isOpen(final State state) {
+ return state == State.OPEN;
+ }
+
+ protected void changeState(final State newState) {
+ state.compareAndSet(newState.oppositeState(), newState);
+ }
+
+ public boolean checkState() {
+ return performStateCheck(0);
+ }
+
+ public boolean incrementAndCheckState(final Integer increment) {
+ return performStateCheck(increment);
+ }
+
+ private boolean performStateCheck(final int increment) {
+ CheckIntervalData currentData;
+ CheckIntervalData nextData;
+ State currentState;
+ do {
+ final long time = now();
+ currentState = state.get();
+ currentData = checkIntervalData.get();
+ nextData = nextCheckIntervalData(increment, currentData, currentState, time);
+ } while (!updateCheckIntervalData(currentData, nextData));
+ if (stateStrategy(currentState).isStateTransition(this, currentData, nextData)) {
+ currentState = currentState.oppositeState();
+ changeStateAndStartNewCheckInterval(currentState);
+ }
+ return !isOpen(currentState);
+ }
+
+ private boolean updateCheckIntervalData(final CheckIntervalData currentData,
+ final CheckIntervalData nextData) {
+ return currentData == nextData
+ || checkIntervalData.compareAndSet(currentData, nextData);
+ }
+
+ private void changeStateAndStartNewCheckInterval(final State newState) {
+ changeState(newState);
+ checkIntervalData.set(new CheckIntervalData(0, now()));
+ }
+
+ private CheckIntervalData nextCheckIntervalData(final int increment,
+ final CheckIntervalData currentData, final State currentState, final long time) {
+ CheckIntervalData nextData;
+ if (stateStrategy(currentState).isCheckIntervalFinished(this, currentData, time)) {
+ nextData = new CheckIntervalData(increment, time);
+ } else {
+ nextData = currentData.increment(increment);
+ }
+ return nextData;
+ }
+
+ static long now() {
+ return System.nanoTime();
+ }
+
+ private static StateStrategy stateStrategy(final State state) {
+ return STRATEGY_MAP.get(state);
+ }
+
+ private static Map<State, StateStrategy> createStrategyMap() {
+ final Map<State, StateStrategy> map = new EnumMap<>(State.class);
+ map.put(State.CLOSED, new StateStrategyClosed());
+ map.put(State.OPEN, new StateStrategyOpen());
+ return map;
+ }
+
+ private static class CheckIntervalData {
+ private final int eventCount;
+ private final long checkIntervalStart;
+
+ CheckIntervalData(final int count, final long intervalStart) {
+ eventCount = count;
+ checkIntervalStart = intervalStart;
+ }
+
+ private CheckIntervalData increment(final int delta) {
+ return (delta == 0) ? this : new CheckIntervalData(eventCount + delta, checkIntervalStart);
+ }
+ }
+
+ private abstract static class StateStrategy {
+ private boolean isCheckIntervalFinished(final CircuitBreakerImpl breaker,
+ final CheckIntervalData currentData, final long now) {
+ return now - currentData.checkIntervalStart > fetchCheckInterval(breaker);
+ }
+
+ public abstract boolean isStateTransition(CircuitBreakerImpl breaker,
+ CheckIntervalData currentData, CheckIntervalData nextData);
+
+ protected abstract long fetchCheckInterval(CircuitBreakerImpl breaker);
+ }
+
+ private static class StateStrategyClosed extends StateStrategy {
+ @Override
+ public boolean isStateTransition(final CircuitBreakerImpl breaker,
+ final CheckIntervalData currentData, final CheckIntervalData nextData) {
+ final long now = now();
+ return nextData.eventCount > breaker.openingThreshold ||
+ (now != currentData.checkIntervalStart && (currentData.eventCount / (now - currentData.checkIntervalStart)) > breaker.failureRatio);
+ }
+
+ @Override
+ protected long fetchCheckInterval(final CircuitBreakerImpl breaker) {
+ return breaker.openingInterval;
+ }
+ }
+
+ private static class StateStrategyOpen extends StateStrategy {
+ @Override
+ public boolean isStateTransition(final CircuitBreakerImpl breaker,
+ final CheckIntervalData currentData, final CheckIntervalData nextData) {
+ return nextData.checkIntervalStart != currentData.checkIntervalStart
+ && currentData.eventCount < breaker.closingThreshold;
+ }
+
+ @Override
+ protected long fetchCheckInterval(final CircuitBreakerImpl breaker) {
+ return breaker.closingInterval;
+ }
+ }
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreaker.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreaker.java
deleted file mode 100644
index 2a65df5..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreaker.java
+++ /dev/null
@@ -1,64 +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.safeguard.impl.circuitbreaker;
-
-import net.jodah.failsafe.CircuitBreaker.State;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-
-public class FailsafeCircuitBreaker implements CircuitBreaker{
- private final FailsafeCircuitBreakerDefinition circuitBreakerDefinition;
-
- public FailsafeCircuitBreaker(FailsafeCircuitBreakerDefinition circuitBreakerDefinition) {
- this.circuitBreakerDefinition = circuitBreakerDefinition;
- }
- @Override
- public FailsafeCircuitBreakerDefinition getDefinition() {
- return circuitBreakerDefinition;
- }
-
- @Override
- public CircuitBreakerState getState() {
- State state = circuitBreakerDefinition.getCircuitBreaker().getState();
- switch(state) {
- case OPEN:
- return CircuitBreakerState.OPEN;
- case CLOSED:
- return CircuitBreakerState.CLOSED;
- case HALF_OPEN:
- return CircuitBreakerState.HALF_OPEN;
- }
- throw new RuntimeException("Unknown state "+state);
- }
-
- public void transitionState(CircuitBreakerState state) {
- switch(state) {
- case OPEN:
- circuitBreakerDefinition.getCircuitBreaker().open();
- break;
- case CLOSED:
- circuitBreakerDefinition.getCircuitBreaker().close();
- break;
- case HALF_OPEN:
- circuitBreakerDefinition.getCircuitBreaker().halfOpen();
- break;
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerBuilder.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerBuilder.java
deleted file mode 100644
index 7fa71f1..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerBuilder.java
+++ /dev/null
@@ -1,91 +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.safeguard.impl.circuitbreaker;
-
-import net.jodah.failsafe.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerBuilder;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.concurrent.TimeUnit;
-
-import static java.util.Arrays.asList;
-
-public class FailsafeCircuitBreakerBuilder implements CircuitBreakerBuilder {
- private final String name;
- private final FailsafeCircuitBreakerManager failsafeCircuitBreakerManager;
- private final CircuitBreaker circuitBreaker;
- private final Collection<Class<? extends Throwable>> failOns;
-
- public FailsafeCircuitBreakerBuilder(String name, FailsafeCircuitBreakerManager failsafeCircuitBreakerManager) {
- this.name = name;
- this.failsafeCircuitBreakerManager = failsafeCircuitBreakerManager;
- this.circuitBreaker = new CircuitBreaker();
- this.failOns = new ArrayList<>();
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withDelay(Duration delay) {
- circuitBreaker.withDelay(delay.toNanos(), TimeUnit.NANOSECONDS);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withFailureCount(int failureCount) {
- circuitBreaker.withFailureThreshold(failureCount);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withFailures(int failureCount, int requestCount) {
- circuitBreaker.withFailureThreshold(failureCount, requestCount);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withSuccessCount(int successCount) {
- circuitBreaker.withSuccessThreshold(successCount);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withSuccesses(int successCount, int requestCount) {
- circuitBreaker.withSuccessThreshold(successCount, requestCount);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerBuilder withFailOn(Class<? extends Throwable>... failOn) {
- this.failOns.addAll(asList(failOn));
- circuitBreaker.failOn(failOn);
- return this;
- }
-
- @Override
- public FailsafeCircuitBreakerDefinition build() {
- if(failOns.isEmpty()) {
- throw new IllegalStateException("At least one exception must be registered for failure detection");
- }
- FailsafeCircuitBreakerDefinition failsafeCircuitBreakerDefinition = new FailsafeCircuitBreakerDefinition(circuitBreaker, failOns);
- this.failsafeCircuitBreakerManager.register(name, failsafeCircuitBreakerDefinition);
- return failsafeCircuitBreakerDefinition;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerDefinition.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerDefinition.java
deleted file mode 100644
index 3ba6866..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerDefinition.java
+++ /dev/null
@@ -1,71 +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.safeguard.impl.circuitbreaker;
-
-import net.jodah.failsafe.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerDefinition;
-
-import java.time.Duration;
-import java.util.Collection;
-
-public class FailsafeCircuitBreakerDefinition implements CircuitBreakerDefinition{
- private final CircuitBreaker circuitBreaker;
- private final Collection<Class<? extends Throwable>> failOnExceptions;
-
- public FailsafeCircuitBreakerDefinition(CircuitBreaker circuitBreaker, Collection<Class<? extends Throwable>> failOnExceptions) {
- this.circuitBreaker = circuitBreaker;
- this.failOnExceptions = failOnExceptions;
- }
-
- @Override
- public Collection<Class<? extends Throwable>> getFailOn() {
- return failOnExceptions;
- }
-
- @Override
- public Duration getDelay() {
- net.jodah.failsafe.util.Duration delay = circuitBreaker.getDelay();
- return Duration.ofMillis(delay.toMillis());
- }
-
- @Override
- public int getRequestVolumeThreshold() {
- return circuitBreaker.getFailureThreshold().denominator;
- }
-
- @Override
- public double getFailureRatio() {
- return circuitBreaker.getFailureThreshold().ratio;
- }
-
- @Override
- public int getSuccessThreshold() {
- return circuitBreaker.getSuccessThreshold().denominator;
- }
-
- @Override
- public double getSuccessRatio() {
- return circuitBreaker.getSuccessThreshold().ratio;
- }
-
- public CircuitBreaker getCircuitBreaker() {
- return circuitBreaker;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerManager.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerManager.java
deleted file mode 100644
index 5fcb866..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/circuitbreaker/FailsafeCircuitBreakerManager.java
+++ /dev/null
@@ -1,46 +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.safeguard.impl.circuitbreaker;
-
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerManager;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Vetoed;
-import java.util.HashMap;
-import java.util.Map;
-
-@Vetoed
-public class FailsafeCircuitBreakerManager implements CircuitBreakerManager{
- private Map<String, FailsafeCircuitBreaker> circuitBreakers = new HashMap<>();;
-
- @Override
- public FailsafeCircuitBreakerBuilder newCircuitBreaker(String name) {
- return new FailsafeCircuitBreakerBuilder(name, this);
- }
-
- @Override
- public FailsafeCircuitBreaker getCircuitBreaker(String name) {
- return circuitBreakers.get(name);
- }
-
- void register(String name, FailsafeCircuitBreakerDefinition failsafeCircuitBreakerDefinition) {
- this.circuitBreakers.put(name, new FailsafeCircuitBreaker(failsafeCircuitBreakerDefinition));
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigFacadeFacade.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigFacadeFacade.java
deleted file mode 100644
index 05b5854..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigFacadeFacade.java
+++ /dev/null
@@ -1,71 +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.safeguard.impl.config;
-
-import java.time.temporal.ChronoUnit;
-
-import javax.annotation.Priority;
-
-import org.apache.safeguard.api.config.ConfigFacade;
-
-@Priority(1)
-public class ConfigFacadeFacade extends ConfigFacade {
- private final ConfigFacade delegate = loadDelegate();
-
- private ConfigFacade loadDelegate() {
- final ClassLoader loader = Thread.currentThread().getContextClassLoader();
- try {
- final Class<?> loadClass = loader.loadClass("org.eclipse.microprofile.config.ConfigProvider");
- loadClass.getMethod("getConfig").invoke(null);
- return new MicroProfileConfigFacade();
- } catch (final Throwable notHere) {
- return new DefaultConfigFacade();
- }
- }
-
- @Override
- public boolean getBoolean(final String name, final boolean defaultValue) {
- return delegate.getBoolean(name, defaultValue);
- }
-
- @Override
- public long getLong(final String name, final long defaultValue) {
- return delegate.getLong(name, defaultValue);
- }
-
- @Override
- public int getInt(final String name, final int defaultValue) {
- return delegate.getInt(name, defaultValue);
- }
-
- @Override
- public double getDouble(final String name, final double defaultValue) {
- return delegate.getDouble(name, defaultValue);
- }
-
- @Override
- public ChronoUnit getChronoUnit(final String name, final ChronoUnit defaultValue) {
- return delegate.getChronoUnit(name, defaultValue);
- }
-
- @Override
- public Class<? extends Throwable>[] getThrowableClasses(final String name, final Class<? extends Throwable>[] defaultValue) {
- return delegate.getThrowableClasses(name, defaultValue);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java
new file mode 100644
index 0000000..bd9ee46
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/ConfigurationMapper.java
@@ -0,0 +1,115 @@
+/*
+ * 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.config;
+
+import static java.util.Optional.ofNullable;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.time.temporal.ChronoUnit;
+import java.util.stream.Stream;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+@ApplicationScoped
+public class ConfigurationMapper {
+ @Inject
+ private GeronimoFaultToleranceConfig config;
+
+ public <T extends Annotation> T map(final T instance, final Method sourceMethod, final Class<T> api) {
+ return api.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ new Class<?>[]{api, Enabled.class}, (proxy, method, args) -> {
+ if (method.getDeclaringClass() == Object.class) {
+ return method.invoke(instance, args);
+ }
+ return findConfiguredValue(instance, api, sourceMethod, method, args);
+ }));
+ }
+
+ private <T extends Annotation> Object findConfiguredValue(final T instance, final Class<T> api,
+ final Method sourceMethod,
+ final Method proxyMethod, final Object[] args) {
+ return ofNullable(ofNullable(findDefaultConfiguration(proxyMethod))
+ .orElseGet(() -> ofNullable(findMethodConfiguration(api, sourceMethod, proxyMethod))
+ .orElseGet(() -> ofNullable(findClassConfiguration(api, sourceMethod, proxyMethod)).orElse(null))))
+ .map(v -> coerce(v, proxyMethod.getReturnType()))
+ .orElseGet(() -> {
+ try {
+ return proxyMethod.invoke(instance, args);
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ throw new IllegalStateException(e.getTargetException());
+ }
+ });
+ }
+
+ private String findDefaultConfiguration(final Method api) {
+ return config.read(String.format("%s/%s", api.getDeclaringClass().getSimpleName(), api.getName()));
+ }
+
+ private <T extends Annotation> String findClassConfiguration(final Class<T> api, final Method beanMethod, final Method apiMethod) {
+ return config.read(String.format("%s/%s/%s",
+ beanMethod.getDeclaringClass().getName(), api.getSimpleName(), apiMethod.getName()));
+ }
+
+ private <T extends Annotation> String findMethodConfiguration(final Class<T> api, final Method beanMethod, final Method apiMethod) {
+ return config.read(String.format("%s/%s/%s/%s",
+ beanMethod.getDeclaringClass().getName(), beanMethod.getName(), api.getSimpleName(), apiMethod.getName()));
+ }
+
+ private Object coerce(final String raw, final Class<?> expected) {
+ if (expected == long.class || expected == Long.class) {
+ return Long.valueOf(raw);
+ }
+ if (expected == double.class || expected == Double.class) {
+ return Double.valueOf(raw);
+ }
+ if (expected == int.class || expected == Integer.class) {
+ return Integer.valueOf(raw);
+ }
+ if (expected == boolean.class || expected == Boolean.class) {
+ return Boolean.valueOf(raw);
+ }
+ if (expected == ChronoUnit.class) {
+ return ChronoUnit.valueOf(raw);
+ }
+ if (expected == String.class) {
+ return raw;
+ }
+ if (expected == Class[].class) {
+ return Stream.of(raw.split(","))
+ .map(String::trim)
+ .filter(it -> !it.isEmpty())
+ .map(it -> {
+ try {
+ return Thread.currentThread().getContextClassLoader().loadClass(it);
+ } catch (final ClassNotFoundException e) {
+ throw new IllegalArgumentException(e);
+ }
+ })
+ .toArray();
+ }
+ throw new IllegalArgumentException("Unsupported: " + expected);
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/DefaultConfigFacade.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/DefaultConfigFacade.java
deleted file mode 100644
index 43c4ff5..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/DefaultConfigFacade.java
+++ /dev/null
@@ -1,75 +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.safeguard.impl.config;
-
-import java.time.temporal.ChronoUnit;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import javax.annotation.Priority;
-
-import org.apache.safeguard.api.config.ConfigFacade;
-import org.eclipse.microprofile.config.Config;
-import org.eclipse.microprofile.config.ConfigProvider;
-
-class DefaultConfigFacade extends ConfigFacade {
- @Override
- public boolean getBoolean(String name, boolean defaultValue) {
- return getOptionalValue(name).map(Boolean::parseBoolean).orElse(defaultValue);
- }
-
- @Override
- public long getLong(String name, long defaultValue) {
- return getOptionalValue(name).map(Long::parseLong).orElse(defaultValue);
- }
-
- @Override
- public int getInt(String name, int defaultValue) {
- return getOptionalValue(name).map(Integer::parseInt).orElse(defaultValue);
- }
-
- @Override
- public double getDouble(String name, double defaultValue) {
- return getOptionalValue(name).map(Double::parseDouble).orElse(defaultValue);
- }
-
- @Override
- public ChronoUnit getChronoUnit(String name, ChronoUnit defaultValue) {
- return getOptionalValue(name).map(ChronoUnit::valueOf).orElse(defaultValue);
- }
-
- @Override
- public Class<? extends Throwable>[] getThrowableClasses(String name, Class<? extends Throwable>[] defaultValue) {
- return getOptionalValue(name).map(value -> {
- final ClassLoader loader = Thread.currentThread().getContextClassLoader();
- return Stream.of(name.split(",")).map(clazz -> {
- try {
- return loader.loadClass(clazz.trim());
- } catch (final ClassNotFoundException e) {
- throw new IllegalArgumentException(e);
- }
- }).toArray(Class[]::new);
- }).orElse(defaultValue);
- }
-
- private Optional<String> getOptionalValue(final String name) {
- return Optional.ofNullable(Optional.ofNullable(System.getenv(name)).orElseGet(() -> System.getProperty(name)));
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/Enabled.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/Enabled.java
new file mode 100644
index 0000000..6472729
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/Enabled.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * 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 org.apache.safeguard.impl.config;
+
+public interface Enabled {
+ boolean enabled();
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/FaultToleranceConfigMpConfigImpl.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/FaultToleranceConfigMpConfigImpl.java
new file mode 100644
index 0000000..4fea947
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/FaultToleranceConfigMpConfigImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.safeguard.impl.config;
+
+import javax.enterprise.inject.Vetoed;
+
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+
+@Vetoed
+public class FaultToleranceConfigMpConfigImpl implements GeronimoFaultToleranceConfig {
+ private final Config config;
+
+ FaultToleranceConfigMpConfigImpl() {
+ config = ConfigProvider.getConfig();
+ }
+
+ @Override
+ public String read(final String key) {
+ return config.getOptionalValue(key, String.class).orElse(null);
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/GeronimoFaultToleranceConfig.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/GeronimoFaultToleranceConfig.java
new file mode 100644
index 0000000..a525d25
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/GeronimoFaultToleranceConfig.java
@@ -0,0 +1,78 @@
+/*
+ * 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.config;
+
+import static java.util.Comparator.comparing;
+import static java.util.Optional.ofNullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import javax.annotation.Priority;
+import javax.enterprise.inject.Vetoed;
+
+@Vetoed
+class DefaultFaultToleranceConfig implements GeronimoFaultToleranceConfig {
+ private final Map<String, String> configuration = new HashMap<>();
+
+ DefaultFaultToleranceConfig() {
+ System.getProperties().stringPropertyNames()
+ .forEach(k -> configuration.put(k, System.getProperty(k)));
+ try (final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/geronimo/microprofile/fault-tolerance.properties")) {
+ if (stream != null) {
+ final Properties properties = new Properties();
+ properties.load(stream);
+ properties.stringPropertyNames().forEach(k -> configuration.put(k, properties.getProperty(k)));
+ }
+ } catch (final IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public String read(final String value) {
+ return configuration.get(value);
+ }
+}
+
+@FunctionalInterface
+public interface GeronimoFaultToleranceConfig {
+
+ String read(String value);
+
+ static GeronimoFaultToleranceConfig create() {
+ try {
+ final Optional<GeronimoFaultToleranceConfig> iterator = StreamSupport.stream(
+ ServiceLoader.load(GeronimoFaultToleranceConfig.class).spliterator(), false)
+ .min(comparing(it -> ofNullable(it.getClass().getAnnotation(Priority.class)).map(Priority::value).orElse(0)));
+ if (iterator.isPresent()) {
+ return new WrappedConfig(iterator.orElseThrow(IllegalStateException::new));
+ }
+ return new WrappedConfig(new FaultToleranceConfigMpConfigImpl());
+ } catch (final ServiceConfigurationError | ExceptionInInitializerError | NoClassDefFoundError | Exception e) {
+ // no-op
+ }
+ return new WrappedConfig(new DefaultFaultToleranceConfig());
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroProfileConfigFacade.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroProfileConfigFacade.java
deleted file mode 100644
index 473797a..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroProfileConfigFacade.java
+++ /dev/null
@@ -1,68 +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.safeguard.impl.config;
-
-import java.time.temporal.ChronoUnit;
-
-import org.apache.safeguard.api.config.ConfigFacade;
-import org.eclipse.microprofile.config.Config;
-import org.eclipse.microprofile.config.ConfigProvider;
-
-class MicroProfileConfigFacade extends ConfigFacade {
- private final Config config;
-
- public MicroProfileConfigFacade() {
- this(ConfigProvider.getConfig());
- }
-
- public MicroProfileConfigFacade(Config config) {
- this.config = config;
- }
-
- @Override
- public boolean getBoolean(String name, boolean defaultValue) {
- return config.getOptionalValue(name, Boolean.class).orElse(defaultValue);
- }
-
- @Override
- public long getLong(String name, long defaultValue) {
- return config.getOptionalValue(name, Long.class).orElse(defaultValue);
- }
-
- @Override
- public int getInt(String name, int defaultValue) {
- return config.getOptionalValue(name, Integer.class).orElse(defaultValue);
- }
-
- @Override
- public double getDouble(String name, double defaultValue) {
- return config.getOptionalValue(name, Double.class).orElse(defaultValue);
- }
-
- @Override
- public ChronoUnit getChronoUnit(String name, ChronoUnit defaultValue) {
- return config.getOptionalValue(name, ChronoUnit.class).orElse(defaultValue);
- }
-
- @Override
- public Class<? extends Throwable>[] getThrowableClasses(String name, Class<? extends Throwable>[] defaultValue) {
- return config.getOptionalValue(name, Class[].class).orElse(defaultValue);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroprofileAnnotationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroprofileAnnotationMapper.java
deleted file mode 100644
index 4387095..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/MicroprofileAnnotationMapper.java
+++ /dev/null
@@ -1,204 +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.safeguard.impl.config;
-
-import org.apache.safeguard.api.config.ConfigFacade;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerBuilder;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerDefinition;
-import org.apache.safeguard.impl.retry.FailsafeRetryBuilder;
-import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Retry;
-
-import javax.enterprise.inject.Vetoed;
-import java.lang.reflect.Method;
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
-import java.util.concurrent.TimeoutException;
-
-@Vetoed
-public class MicroprofileAnnotationMapper {
- private static MicroprofileAnnotationMapper INSTANCE = new MicroprofileAnnotationMapper();
- private final ConfigFacade configFacade;
-
- private MicroprofileAnnotationMapper() {
- this(ConfigFacade.getInstance());
- }
- public MicroprofileAnnotationMapper(ConfigFacade configFacade) {
- this.configFacade = configFacade;
- }
-
- private static final String RETRY_CLASS_FORMAT = "%s/Retry/%s";
- private static final String RETRY_METHOD_FORMAT = "%s/%s/Retry/%s";
- private static final String CIRCUIT_BREAKER_CLASS_FORMAT = "%s/CircuitBreaker/%s";
- private static final String CIRCUIT_BREAKER_METHOD_FORMAT = "%s/%s/CircuitBreaker/%s";
- public FailsafeRetryDefinition mapRetry(Method method, Retry retry, FailsafeRetryBuilder retryBuilder) {
- boolean methodLevel = method.isAnnotationPresent(Retry.class);
- int maxRetries = getRetryValue(method, "maxRetries", methodLevel, retry.maxRetries());
- Class[] retryOn = getRetryValue(method, "retryOn", methodLevel, retry.retryOn());
- Class[] abortOn = getRetryValue(method, "abortOn", methodLevel, retry.abortOn());
-
- long delay = getRetryValue(method, "delay", methodLevel, retry.delay());
- ChronoUnit delayUnit = getRetryValue(method, "delayUnit", methodLevel, retry.delayUnit());
-
- long jitter = getRetryValue(method, "jitter", methodLevel, retry.jitter());
- ChronoUnit jitterUnit = getRetryValue(method, "jitterDelayUnit", methodLevel, retry.jitterDelayUnit());
-
- long maxDuration = getRetryValue(method, "maxDuration", methodLevel, retry.maxDuration());
- ChronoUnit maxDurationUnit = getRetryValue(method, "durationUnit", methodLevel, retry.durationUnit());
-
- retryBuilder.withMaxRetries(maxRetries)
- .withRetryOn(retryOn)
- .withRetryOn(TimeoutException.class, org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException.class)
- .withAbortOn(abortOn);
- if (delay > 0L) {
- retryBuilder.withDelay(Duration.of(delay, delayUnit));
- }
- if (jitter > 0L) {
- retryBuilder.withJitter(Duration.of(jitter, jitterUnit));
- }
- if (maxDuration > 0L) {
- retryBuilder.withMaxDuration(Duration.of(maxDuration, maxDurationUnit));
- }
- return retryBuilder.build();
- }
-
- public FailsafeCircuitBreakerDefinition mapCircuitBreaker(Method method, CircuitBreaker circuitBreaker,
- FailsafeCircuitBreakerBuilder builder) {
- boolean methodLevel = method.isAnnotationPresent(CircuitBreaker.class);
-
- double failureRatio = getCBValue(method, "failureRatio", methodLevel, circuitBreaker.failureRatio());
- int requestVolumeThreshold = getCBValue(method, "requestVolumeThreshold", methodLevel, circuitBreaker.requestVolumeThreshold());
- Class[] failOn = getCBValue(method, "failOn", methodLevel, circuitBreaker.failOn());
- long delay = getCBValue(method, "delay", methodLevel, circuitBreaker.delay());
- ChronoUnit delayUnit = getCBValue(method, "delayUnit", methodLevel, circuitBreaker.delayUnit());
- int successThreshold = getCBValue(method, "successThreshold", methodLevel, circuitBreaker.successThreshold());
-
- int failureCount = (int) (failureRatio * requestVolumeThreshold);
- FailsafeCircuitBreakerBuilder failsafeCircuitBreakerBuilder = builder
- .withFailOn(failOn)
- .withFailOn(TimeoutException.class, org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException.class)
- .withDelay(Duration.of(delay, delayUnit))
- .withSuccessCount(successThreshold);
- if (failureCount > 0) {
- failsafeCircuitBreakerBuilder.withFailures(failureCount, requestVolumeThreshold);
- }
- return failsafeCircuitBreakerBuilder.build();
- }
-
- public static MicroprofileAnnotationMapper getInstance() {
- return INSTANCE;
- }
-
- public static void setInstance(MicroprofileAnnotationMapper microprofileAnnotationMapper) {
- INSTANCE = microprofileAnnotationMapper;
- }
-
- // retry config
- private int getRetryValue(Method method, String name, boolean isMethod, int defaultValue) {
- String methodKey = String.format(RETRY_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- int value = configFacade.getInt(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(RETRY_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getInt(classKey, defaultValue);
- }
-
- private long getRetryValue(Method method, String name, boolean isMethod, long defaultValue) {
- String methodKey = String.format(RETRY_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- long value = configFacade.getLong(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(RETRY_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getLong(classKey, defaultValue);
- }
-
- private ChronoUnit getRetryValue(Method method, String name, boolean isMethod, ChronoUnit defaultValue) {
- String methodKey = String.format(RETRY_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- ChronoUnit value = configFacade.getChronoUnit(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(RETRY_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getChronoUnit(classKey, defaultValue);
- }
-
- private Class[] getRetryValue(Method method, String name, boolean isMethod, Class[] defaultValue) {
- String methodKey = String.format(RETRY_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- Class[] value = configFacade.getThrowableClasses(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(RETRY_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getThrowableClasses(classKey, defaultValue);
- }
- // circuit breaker config
- private int getCBValue(Method method, String name, boolean isMethod, int defaultValue) {
- String methodKey = String.format(CIRCUIT_BREAKER_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- int value = configFacade.getInt(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(CIRCUIT_BREAKER_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getInt(classKey, defaultValue);
- }
-
- private long getCBValue(Method method, String name, boolean isMethod, long defaultValue) {
- String methodKey = String.format(CIRCUIT_BREAKER_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- long value = configFacade.getLong(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(CIRCUIT_BREAKER_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getLong(classKey, defaultValue);
- }
-
- private double getCBValue(Method method, String name, boolean isMethod, double defaultValue) {
- String methodKey = String.format(CIRCUIT_BREAKER_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- double value = configFacade.getDouble(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(CIRCUIT_BREAKER_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getDouble(classKey, defaultValue);
- }
-
- private ChronoUnit getCBValue(Method method, String name, boolean isMethod, ChronoUnit defaultValue) {
- String methodKey = String.format(CIRCUIT_BREAKER_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- ChronoUnit value = configFacade.getChronoUnit(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(CIRCUIT_BREAKER_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getChronoUnit(classKey, defaultValue);
- }
-
- private Class[] getCBValue(Method method, String name, boolean isMethod, Class[] defaultValue) {
- String methodKey = String.format(CIRCUIT_BREAKER_METHOD_FORMAT, method.getDeclaringClass().getName(), method.getName(), name);
- Class[] value = configFacade.getThrowableClasses(methodKey, defaultValue);
- if(value != defaultValue || isMethod) {
- return value;
- }
- String classKey = String.format(CIRCUIT_BREAKER_CLASS_FORMAT, method.getDeclaringClass().getName(), name);
- return configFacade.getThrowableClasses(classKey, defaultValue);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/WrappedConfig.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/WrappedConfig.java
new file mode 100644
index 0000000..03bf68b
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/config/WrappedConfig.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.safeguard.impl.config;
+
+import static java.util.Optional.ofNullable;
+
+class WrappedConfig implements GeronimoFaultToleranceConfig {
+ private final GeronimoFaultToleranceConfig delegate;
+
+ WrappedConfig(final GeronimoFaultToleranceConfig config) {
+ this.delegate = config;
+ }
+
+ @Override
+ public String read(final String value) {
+ return ofNullable(delegate.read(value)).orElseGet(() -> delegate.read("geronimo.safeguard." + value));
+ }
+}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/SafeguardEnabled.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/customizable/Safeguard.java
similarity index 60%
rename from safeguard-api/src/main/java/org/apache/safeguard/api/SafeguardEnabled.java
rename to safeguard-impl/src/main/java/org/apache/safeguard/impl/customizable/Safeguard.java
index 4396a9b..931ea35 100644
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/SafeguardEnabled.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/customizable/Safeguard.java
@@ -16,21 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.safeguard.impl.customizable;
-package org.apache.safeguard.api;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import javax.enterprise.util.AnnotationLiteral;
-import javax.interceptor.InterceptorBinding;
-import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-@InterceptorBinding
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface SafeguardEnabled {
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Qualifier;
- SafeguardEnabled INSTANCE = new Literal();
- class Literal extends AnnotationLiteral<SafeguardEnabled> implements SafeguardEnabled {}
+@Qualifier
+@Retention(RUNTIME)
+@Target({METHOD, TYPE, FIELD})
+public @interface Safeguard {
+ final class Literal extends AnnotationLiteral<Safeguard> implements Safeguard {
+ public static final Literal INSTANCE = new Literal();
+
+ private static final long serialVersionUID = 1L;
+ }
}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncFailsafeExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncFailsafeExecutionPlan.java
deleted file mode 100644
index 3265448..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncFailsafeExecutionPlan.java
+++ /dev/null
@@ -1,78 +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.safeguard.impl.executionPlans;
-
-import net.jodah.failsafe.AsyncFailsafe;
-import net.jodah.failsafe.CircuitBreakerOpenException;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.apache.safeguard.impl.fallback.FallbackRunner;
-import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
-
-import javax.interceptor.InvocationContext;
-import java.time.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class AsyncFailsafeExecutionPlan extends SyncFailsafeExecutionPlan {
- private final ScheduledExecutorService executorService;
- private final Duration timeout;
-
- public AsyncFailsafeExecutionPlan(FailsafeRetryDefinition retryDefinition,
- FailsafeCircuitBreaker failsafeCircuitBreaker,
- FallbackRunner fallback,
- ScheduledExecutorService executorService,
- Duration timeout) {
- super(retryDefinition, failsafeCircuitBreaker, fallback);
- this.executorService = executorService;
- this.timeout = timeout;
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- AsyncFailsafe<?> asyncFailsafe = getSyncFailsafe(invocationContext).with(executorService);
- try {
- if (this.timeout == null) {
- return asyncFailsafe.get(callable).get();
- } else {
- return asyncFailsafe
- .get(new TimeoutWrappedCallable<>(callable, executorService, timeout,
- super.failsafeCircuitBreaker))
- .get();
- }
- } catch (CircuitBreakerOpenException e) {
- throw new org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException(e);
- } catch (InterruptedException | ExecutionException e) {
- Throwable cause = e.getCause();
- if(cause == null) {
- throw new RuntimeException(e);
- }
- if (cause instanceof CircuitBreakerOpenException) {
- throw new org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException(cause);
- }
- else if(cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- }
- else {
- throw new RuntimeException(e);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlan.java
deleted file mode 100644
index e1a708b..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlan.java
+++ /dev/null
@@ -1,46 +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.safeguard.impl.executionPlans;
-
-import org.apache.safeguard.exception.AsyncException;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-class AsyncOnlyExecutionPlan implements ExecutionPlan {
- private final ExecutorService executorService;
-
- AsyncOnlyExecutionPlan(ExecutorService executorService) {
- this.executorService = executorService;
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- Future<T> submitted = executorService.submit(callable);
- try {
- return submitted.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new AsyncException(e);
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlan.java
deleted file mode 100644
index 1c3cd50..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlan.java
+++ /dev/null
@@ -1,56 +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.safeguard.impl.executionPlans;
-
-import javax.interceptor.InvocationContext;
-import java.time.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-class AsyncTimeoutExecutionPlan implements ExecutionPlan {
- private final Duration timeout;
- private final ExecutorService executorService;
-
- AsyncTimeoutExecutionPlan(Duration timeout, ExecutorService executorService) {
- this.timeout = timeout;
- this.executorService = executorService;
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- Future<T> future = executorService.submit(callable);
- try {
- return future.get(timeout.toNanos(), TimeUnit.NANOSECONDS);
- } catch (ExecutionException e) {
- if(e.getCause() != null && e.getCause() instanceof RuntimeException) {
- throw (RuntimeException)e.getCause();
- }
- else {
- throw new RuntimeException(e);
- }
- } catch (InterruptedException | TimeoutException e) {
- throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(e);
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BasicExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BasicExecutionPlan.java
deleted file mode 100644
index 74881d4..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BasicExecutionPlan.java
+++ /dev/null
@@ -1,35 +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.safeguard.impl.executionPlans;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public class BasicExecutionPlan implements ExecutionPlan {
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- try {
- return callable.call();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BulkheadExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BulkheadExecutionPlan.java
deleted file mode 100644
index 6553636..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/BulkheadExecutionPlan.java
+++ /dev/null
@@ -1,50 +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.safeguard.impl.executionPlans;
-
-import org.apache.safeguard.api.bulkhead.Bulkhead;
-import org.apache.safeguard.exception.SafeguardException;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public class BulkheadExecutionPlan implements ExecutionPlan{
- private final Bulkhead bulkhead;
- private ExecutionPlan child;
-
- BulkheadExecutionPlan(Bulkhead bulkhead) {
- this.bulkhead = bulkhead;
- }
-
- void setChild(ExecutionPlan child) {
- this.child = child;
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- if(bulkhead != null && child != null) {
- return child.execute(() -> bulkhead.execute(callable), invocationContext);
- } else if(child != null) {
- return child.execute(callable, invocationContext);
- } else {
- throw new SafeguardException("Neither bulkhead nor child specified");
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlan.java
deleted file mode 100644
index 590eaff..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlan.java
+++ /dev/null
@@ -1,27 +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.safeguard.impl.executionPlans;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public interface ExecutionPlan {
- <T> T execute(Callable<T> callable, InvocationContext invocationContext);
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlanFactory.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlanFactory.java
deleted file mode 100644
index ae5ba7f..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlanFactory.java
+++ /dev/null
@@ -1,201 +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.safeguard.impl.executionPlans;
-
-import org.apache.safeguard.api.bulkhead.Bulkhead;
-import org.apache.safeguard.api.bulkhead.BulkheadBuilder;
-import org.apache.safeguard.api.bulkhead.BulkheadManager;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerBuilder;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerDefinition;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerManager;
-import org.apache.safeguard.api.config.ConfigFacade;
-import org.apache.safeguard.impl.config.MicroprofileAnnotationMapper;
-import org.apache.safeguard.impl.executorService.ExecutorServiceProvider;
-import org.apache.safeguard.impl.fallback.FallbackRunner;
-import org.apache.safeguard.impl.retry.FailsafeRetryBuilder;
-import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
-import org.apache.safeguard.impl.retry.FailsafeRetryManager;
-import org.apache.safeguard.impl.util.NamingUtil;
-import org.eclipse.microprofile.faulttolerance.Asynchronous;
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Fallback;
-import org.eclipse.microprofile.faulttolerance.Retry;
-import org.eclipse.microprofile.faulttolerance.Timeout;
-
-import java.lang.reflect.Method;
-import java.time.Duration;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-
-import static org.apache.safeguard.impl.util.AnnotationUtil.getAnnotation;
-
-public class ExecutionPlanFactory {
- private final FailsafeCircuitBreakerManager circuitBreakerManager;
- private final FailsafeRetryManager retryManager;
- private final BulkheadManager bulkheadManager;
- private final MicroprofileAnnotationMapper microprofileAnnotationMapper;
- private final ExecutorServiceProvider executorServiceProvider;
- private ConcurrentMap<String, ExecutionPlan> executionPlanMap = new ConcurrentHashMap<>();
- private final boolean enableAllMicroProfileFeatures;
-
- public ExecutionPlanFactory(FailsafeCircuitBreakerManager circuitBreakerManager,
- FailsafeRetryManager retryManager,
- BulkheadManager bulkheadManager,
- MicroprofileAnnotationMapper microprofileAnnotationMapper,
- ExecutorServiceProvider executorServiceProvider) {
- this.circuitBreakerManager = circuitBreakerManager;
- this.retryManager = retryManager;
- this.bulkheadManager = bulkheadManager;
- this.microprofileAnnotationMapper = microprofileAnnotationMapper;
- this.executorServiceProvider = executorServiceProvider;
- this.enableAllMicroProfileFeatures = this.enableNonFallbacksForMicroProfile();
- }
-
- public ExecutionPlan locateExecutionPlan(String name, Duration timeout, boolean async) {
- return executionPlanMap.computeIfAbsent(name, key -> {
- FailsafeCircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(key);
- FailsafeRetryDefinition retryDefinition = retryManager.getRetryDefinition(key);
- if (circuitBreaker == null && retryDefinition == null) {
- return null;
- } else {
- return new SyncFailsafeExecutionPlan(retryDefinition, circuitBreaker, null);
- }
- });
- }
-
- public ExecutionPlan locateExecutionPlan(Method method) {
- final String name = NamingUtil.createName(method);
- return executionPlanMap.computeIfAbsent(name, key -> {
- FailsafeCircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(name);
- if (circuitBreaker == null) {
- circuitBreaker = createCBDefinition(name, method);
- }
- FailsafeRetryDefinition retryDefinition = retryManager.getRetryDefinition(name);
- if (retryDefinition == null) {
- retryDefinition = createDefinition(name, method);
- }
- Bulkhead bulkhead = bulkheadManager.getBulkhead(name);
- if (bulkhead == null) {
- bulkhead = createBulkhead(name, method);
- }
- boolean isAsync = isAsync(method);
- Duration timeout = readTimeout(method);
- FallbackRunner fallbackRunner = this.createFallback(method);
- if(this.enableAllMicroProfileFeatures) {
- BulkheadExecutionPlan parent = new BulkheadExecutionPlan(bulkhead);
- if (circuitBreaker == null && retryDefinition == null && isAsync) {
- if (timeout == null) {
- parent.setChild(new AsyncOnlyExecutionPlan(executorServiceProvider.getExecutorService()));
- } else {
- parent.setChild(new AsyncTimeoutExecutionPlan(timeout, executorServiceProvider.getExecutorService()));
- }
- } else if (circuitBreaker == null && retryDefinition == null && timeout != null) {
- // then its just timeout
- parent.setChild(new AsyncTimeoutExecutionPlan(timeout, executorServiceProvider.getExecutorService()));
- } else {
- if (isAsync || timeout != null) {
- parent.setChild(new AsyncFailsafeExecutionPlan(retryDefinition, circuitBreaker, fallbackRunner,
- executorServiceProvider.getScheduledExecutorService(), timeout));;
- } else if(circuitBreaker == null && retryDefinition == null && fallbackRunner == null) {
- parent.setChild(new BasicExecutionPlan());
- } else if(circuitBreaker == null && retryDefinition == null) {
- parent.setChild(new FallbackOnlyExecutionPlan(fallbackRunner));
- } else {
- parent.setChild(new SyncFailsafeExecutionPlan(retryDefinition, circuitBreaker, fallbackRunner));
- }
- }
- return parent;
- }else {
- if(fallbackRunner == null) {
- return new BasicExecutionPlan();
- }
- else {
- return new FallbackOnlyExecutionPlan(fallbackRunner);
- }
- }
-
- });
- }
-
- private boolean enableNonFallbacksForMicroProfile() {
- return ConfigFacade.getInstance().getBoolean("MP_Fault_Tolerance_NonFallback_Enabled", true);
- }
-
- private FailsafeRetryDefinition createDefinition(String name, Method method) {
- Retry retry = getAnnotation(method, Retry.class);
- if (retry == null) {
- return null;
- }
- FailsafeRetryBuilder retryBuilder = retryManager.newRetryDefinition(name);
- return microprofileAnnotationMapper.mapRetry(method, retry, retryBuilder);
- }
-
- private FailsafeCircuitBreaker createCBDefinition(String name, Method method) {
- CircuitBreaker circuitBreaker = getAnnotation(method, CircuitBreaker.class);
- if (circuitBreaker == null) {
- return null;
- }
- FailsafeCircuitBreakerBuilder circuitBreakerBuilder = this.circuitBreakerManager.newCircuitBreaker(name);
- FailsafeCircuitBreakerDefinition circuitBreakerDefinition = microprofileAnnotationMapper.mapCircuitBreaker(method,
- circuitBreaker, circuitBreakerBuilder);
- return new FailsafeCircuitBreaker(circuitBreakerDefinition);
- }
-
- private Bulkhead createBulkhead(String name, Method method) {
- org.eclipse.microprofile.faulttolerance.Bulkhead annotation = getAnnotation(method,
- org.eclipse.microprofile.faulttolerance.Bulkhead.class);
- if (annotation == null) {
- return null;
- }
- boolean async = getAnnotation(method, Asynchronous.class) != null;
- BulkheadBuilder bulkheadBuilder = this.bulkheadManager.newBulkheadBuilder(name)
- .withMaxWaiting(annotation.waitingTaskQueue())
- .withMaxConcurrency(annotation.value());
- if(async) {
- bulkheadBuilder.asynchronous();
- }
- bulkheadBuilder.build();
- return bulkheadManager.getBulkhead(name);
- }
-
- private FallbackRunner createFallback(Method method) {
- Fallback fallback = getAnnotation(method, Fallback.class);
- if(fallback == null) {
- return null;
- }
- String methodName = "".equals(fallback.fallbackMethod()) ? null : fallback.fallbackMethod();
- return new FallbackRunner(fallback.value(), methodName);
- }
-
- private boolean isAsync(Method method) {
- return getAnnotation(method, Asynchronous.class) != null &&
- getAnnotation(method, org.eclipse.microprofile.faulttolerance.Bulkhead.class) == null;
- }
-
- private Duration readTimeout(Method method) {
- Timeout timeout = getAnnotation(method, Timeout.class);
- if(timeout == null) {
- return null;
- }
- return Duration.of(timeout.value(), timeout.unit());
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/FallbackOnlyExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/FallbackOnlyExecutionPlan.java
deleted file mode 100644
index 57f56e7..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/FallbackOnlyExecutionPlan.java
+++ /dev/null
@@ -1,43 +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.safeguard.impl.executionPlans;
-
-import org.apache.safeguard.impl.fallback.FallbackRunner;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public class FallbackOnlyExecutionPlan implements ExecutionPlan {
- private final FallbackRunner fallbackRunner;
-
- public FallbackOnlyExecutionPlan(FallbackRunner fallbackRunner) {
- this.fallbackRunner = fallbackRunner;
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- try {
- return callable.call();
- }
- catch (Exception e) {
- return (T)fallbackRunner.executeFallback(invocationContext);
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlan.java
deleted file mode 100644
index 0eec4ad..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlan.java
+++ /dev/null
@@ -1,80 +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.safeguard.impl.executionPlans;
-
-import net.jodah.failsafe.CircuitBreakerOpenException;
-import net.jodah.failsafe.Failsafe;
-import net.jodah.failsafe.SyncFailsafe;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.apache.safeguard.impl.fallback.FallbackRunner;
-import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
-
-import javax.interceptor.InvocationContext;
-import java.util.concurrent.Callable;
-
-public class SyncFailsafeExecutionPlan implements ExecutionPlan {
- protected final FailsafeRetryDefinition retryDefinition;
- protected final FailsafeCircuitBreaker failsafeCircuitBreaker;
- private final FallbackRunner fallback;
-
- SyncFailsafeExecutionPlan(FailsafeRetryDefinition retryDefinition, FailsafeCircuitBreaker failsafeCircuitBreaker, FallbackRunner fallback) {
- this.retryDefinition = retryDefinition;
- this.failsafeCircuitBreaker = failsafeCircuitBreaker;
- this.fallback = fallback;
- validateConfig();
- }
-
- private void validateConfig() {
- if(retryDefinition == null && failsafeCircuitBreaker == null) {
- throw new IllegalStateException("For non-async invocations, must have at least one of RetryDefintion or CircuitBreaker defined");
- }
- }
-
- @Override
- public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
- SyncFailsafe<?> syncFailsafe = getSyncFailsafe(invocationContext);
- try {
- return syncFailsafe.get(callable);
- } catch (CircuitBreakerOpenException e) {
- throw new org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException(e);
- }
- }
-
- SyncFailsafe<?> getSyncFailsafe(InvocationContext invocationContext) {
- SyncFailsafe<?> syncFailsafe;
- Callable callable = () -> fallback.executeFallback(invocationContext);
- if(retryDefinition == null) {
- syncFailsafe = Failsafe.with(failsafeCircuitBreaker.getDefinition().getCircuitBreaker());
- }
- else {
- if(failsafeCircuitBreaker == null) {
- syncFailsafe = Failsafe.with(retryDefinition.getRetryPolicy());
- }
- else {
- syncFailsafe = Failsafe.with(retryDefinition.getRetryPolicy())
- .with(failsafeCircuitBreaker.getDefinition().getCircuitBreaker());
- }
- }
- if(this.fallback != null) {
- syncFailsafe = syncFailsafe.withFallback(callable);
- }
- return syncFailsafe;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/TimeoutWrappedCallable.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/TimeoutWrappedCallable.java
deleted file mode 100644
index 31a9fec..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/TimeoutWrappedCallable.java
+++ /dev/null
@@ -1,88 +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.safeguard.impl.executionPlans;
-
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException;
-import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException;
-
-import java.time.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-class TimeoutWrappedCallable<T> implements Callable<T> {
- private final Callable<T> delegate;
- private final ScheduledExecutorService executorService;
- private final Duration timeout;
- private final FailsafeCircuitBreaker failsafeCircuitBreaker;
- private boolean timedout = false;
-
- TimeoutWrappedCallable(Callable<T> delegate, ScheduledExecutorService executorService, Duration timeout, FailsafeCircuitBreaker failsafeCircuitBreaker) {
- this.delegate = delegate;
- this.executorService = executorService;
- this.timeout = timeout;
- this.failsafeCircuitBreaker = failsafeCircuitBreaker;
- }
-
- @Override
- public T call() throws Exception {
- boolean circuitBreakerOpen = failsafeCircuitBreaker != null && failsafeCircuitBreaker.getState() == CircuitBreakerState.OPEN;
- if(circuitBreakerOpen) {
- throw new CircuitBreakerOpenException();
- }
- ScheduledFuture<?> scheduledFuture = executorService.schedule(new TimerRunnable(Thread.currentThread(), this),
- timeout.toNanos(), TimeUnit.NANOSECONDS);
-
- T result;
- try {
- result = delegate.call();
- } catch (Exception e) {
- throw e;
- } finally {
- scheduledFuture.cancel(true);
- }
- if(timedout) {
- throw new TimeoutException("Execution timed out after " + timeout);
- }
- return result;
- }
-
- private class TimerRunnable implements Runnable {
- private final Thread targetThread;
- private final TimeoutWrappedCallable task;
-
- private boolean doInterrupt = true;
- private TimerRunnable(Thread targetThread, TimeoutWrappedCallable task) {
- this.targetThread = targetThread;
- this.task = task;
- }
-
- @Override
- public void run() {
- if(doInterrupt) {
- task.timedout = true;
- targetThread.interrupt();
- }
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/DefaultExecutorServiceProvider.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/DefaultExecutorServiceProvider.java
deleted file mode 100644
index 9d2d615..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/DefaultExecutorServiceProvider.java
+++ /dev/null
@@ -1,41 +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.safeguard.impl.executorService;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class DefaultExecutorServiceProvider implements ExecutorServiceProvider {
- private final ScheduledExecutorService executorService;
-
- public DefaultExecutorServiceProvider(ScheduledExecutorService executorService) {
- this.executorService = executorService;
- }
-
- @Override
- public ExecutorService getExecutorService() {
- return executorService;
- }
-
- @Override
- public ScheduledExecutorService getScheduledExecutorService() {
- return executorService;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/ExecutorServiceProvider.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/ExecutorServiceProvider.java
deleted file mode 100644
index 55b7694..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executorService/ExecutorServiceProvider.java
+++ /dev/null
@@ -1,31 +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.safeguard.impl.executorService;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ScheduledExecutorService;
-
-/**
- * Wraps the look up of an ExecutorService to handle SE and EE cases
- */
-public interface ExecutorServiceProvider {
- ExecutorService getExecutorService();
- ScheduledExecutorService getScheduledExecutorService();
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java
new file mode 100644
index 0000000..e3e8a61
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackInterceptor.java
@@ -0,0 +1,166 @@
+/*
+ * 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.fallback;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import javax.annotation.PreDestroy;
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.annotation.AnnotationFinder;
+import org.apache.safeguard.impl.cdi.SafeguardExtension;
+import org.eclipse.microprofile.faulttolerance.ExecutionContext;
+import org.eclipse.microprofile.faulttolerance.Fallback;
+import org.eclipse.microprofile.faulttolerance.FallbackHandler;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
+
+// @Fallback - added through the extension since the @Target doesnt allow it
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER)
+public class FallbackInterceptor implements Serializable {
+ @Inject
+ private Cache cache;
+
+ @AroundInvoke
+ public Object withFallback(final InvocationContext context) {
+ final Map<Method, FallbackHandler<?>> handlers = cache.getHandlers();
+ FallbackHandler<?> handler = handlers.get(context.getMethod());
+ if (handler == null) {
+ handler = cache.create(context);
+ handlers.putIfAbsent(context.getMethod(), handler);
+ }
+ try {
+ return context.proceed();
+ } catch (final Throwable e) {
+ return handler.handle(new EnrichedExecutionContext() {
+ @Override
+ public Object getTarget() {
+ return context.getTarget();
+ }
+
+ @Override
+ public Method getMethod() {
+ return context.getMethod();
+ }
+
+ @Override
+ public Object[] getParameters() {
+ return context.getParameters();
+ }
+
+ @Override
+ public Throwable getFailure() {
+ return e;
+ }
+ });
+ }
+ }
+
+ @ApplicationScoped
+ public static class Cache {
+ private final Map<Method, FallbackHandler<?>> handlers = new ConcurrentHashMap<>();
+
+ @Inject
+ private AnnotationFinder finder;
+
+ @Inject
+ private SafeguardExtension extension;
+
+ @Inject
+ private BeanManager beanManager;
+
+ private final Collection<CreationalContext<?>> contexts = new ArrayList<>();
+
+ @PreDestroy
+ private void release() {
+ contexts.forEach(CreationalContext::release);
+ }
+
+ public Map<Method, FallbackHandler<?>> getHandlers() {
+ return handlers;
+ }
+
+ public FallbackHandler<?> create(final InvocationContext context) {
+ final Fallback fallback = finder.findAnnotation(Fallback.class, context);
+ final Class<? extends FallbackHandler<?>> value = fallback.value();
+ final String method = fallback.fallbackMethod();
+ if (!method.isEmpty() && value != Fallback.DEFAULT.class) {
+ throw new FaultToleranceDefinitionException("You can't set a method and handler as fallback on " + context.getMethod());
+ }
+ if (value != Fallback.DEFAULT.class) {
+ Stream.of(value.getInterfaces()).filter(it -> it == FallbackHandler.class)
+ .findFirst()
+ .map(it -> ParameterizedType.class.cast(it))
+ .filter(it -> it.getActualTypeArguments().length == 1)
+ .map(it -> extension.toClass(context.getMethod().getReturnType()).isAssignableFrom(extension.toClass(it.getActualTypeArguments()[0])))
+ .orElseThrow(() -> new FaultToleranceDefinitionException("handler does not match method: " + context.getMethod()));
+ final Set<Bean<?>> beans = beanManager.getBeans(value);
+ final Bean<?> handlerBean = beanManager.resolve(beans);
+ final CreationalContext<Object> creationalContext = beanManager.createCreationalContext(null);
+ if (!beanManager.isNormalScope(handlerBean.getScope())) {
+ contexts.add(creationalContext);
+ }
+ return FallbackHandler.class.cast(beanManager.getReference(handlerBean, FallbackHandler.class, creationalContext));
+ }
+ try {
+ final Method fallbackMethod = context.getTarget().getClass().getMethod(method);
+ if (!extension.toClass(context.getMethod().getReturnType()).isAssignableFrom(extension.toClass(fallbackMethod.getReturnType())) ||
+ !Arrays.equals(context.getMethod().getParameterTypes(), fallbackMethod.getParameterTypes())) {
+ throw new FaultToleranceDefinitionException("handler method does not match method: " + context.getMethod());
+ }
+ if (!fallbackMethod.isAccessible()) {
+ fallbackMethod.setAccessible(true);
+ }
+ return (FallbackHandler<Object>) context1 -> {
+ try {
+ return fallbackMethod.invoke(EnrichedExecutionContext.class.cast(context1).getTarget(), context1.getParameters());
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ throw new IllegalStateException(e.getTargetException());
+ }
+ };
+ } catch (final NoSuchMethodException e) {
+ throw new FaultToleranceDefinitionException("No method " + method + " in " + context.getTarget());
+ }
+ }
+ }
+
+ private interface EnrichedExecutionContext extends ExecutionContext {
+ Object getTarget();
+ }
+}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackRunner.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackRunner.java
deleted file mode 100644
index 26e376e..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/fallback/FallbackRunner.java
+++ /dev/null
@@ -1,102 +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.safeguard.impl.fallback;
-
-import org.eclipse.microprofile.faulttolerance.ExecutionContext;
-import org.eclipse.microprofile.faulttolerance.FallbackHandler;
-
-import javax.enterprise.inject.spi.CDI;
-import javax.interceptor.InvocationContext;
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-
-public class FallbackRunner {
- private final Class<? extends FallbackHandler<?>> handlerClass;
- private final String method;
-
- public FallbackRunner(Class<? extends FallbackHandler<?>> handlerClass, String method) {
- this.handlerClass = handlerClass;
- this.method = method;
- }
-
- public Object executeFallback(InvocationContext invocationContext) {
- if(method != null) {
- try {
- Method method = getMethod(invocationContext.getTarget().getClass());
- Parameter[] parameters = method.getParameters();
- if(parameters.length == 0) {
- return method.invoke(invocationContext.getTarget());
- }
- else {
- return method.invoke(invocationContext.getTarget(), invocationContext.getParameters());
- }
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
- }
- else {
- SafeguardExecutionContext executionContext = new SafeguardExecutionContext(invocationContext.getMethod(),
- invocationContext.getParameters());
- CDI<Object> cdi = CDI.current();
- FallbackHandler fallbackHandler = null;
- try {
- fallbackHandler = cdi.select(handlerClass).get();
- }
- catch (Exception e) {
- try {
- fallbackHandler = handlerClass.newInstance();
- } catch (InstantiationException | IllegalAccessException e1) {
- throw new IllegalArgumentException(e);
- }
- }
- return fallbackHandler.handle(executionContext);
- }
- }
-
- private Method getMethod(Class<?> aClass) {
- for(Method method : aClass.getMethods()) {
- if(method.getName().equals(this.method)) {
- return method;
- }
- }
- return null;
- }
-
- private static class SafeguardExecutionContext implements ExecutionContext {
-
- private final Method method;
- private final Object[] parameters;
-
- private SafeguardExecutionContext(Method method, Object[] parameters) {
- this.method = method;
- this.parameters = parameters;
- }
-
- @Override
- public Method getMethod() {
- return method;
- }
-
- @Override
- public Object[] getParameters() {
- return parameters;
- }
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java
new file mode 100644
index 0000000..ec888d3
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/FaultToleranceMetrics.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.safeguard.impl.metrics;
+
+import static java.util.Comparator.comparing;
+import static java.util.Optional.ofNullable;
+
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.stream.StreamSupport;
+
+import javax.annotation.Priority;
+import javax.enterprise.inject.spi.CDI;
+
+// todo
+public interface FaultToleranceMetrics {
+
+ void inc(String value);
+ void dec(String value);
+
+ static FaultToleranceMetrics create() {
+ try {
+ final Optional<FaultToleranceMetrics> iterator = StreamSupport.stream(
+ ServiceLoader.load(FaultToleranceMetrics.class).spliterator(), false)
+ .min(comparing(it -> ofNullable(it.getClass().getAnnotation(Priority.class)).map(Priority::value).orElse(0)));
+ if (iterator.isPresent()) {
+ return iterator.orElseThrow(IllegalStateException::new);
+ }
+ return new MicroprofileMetricsImpl(CDI.current().select(org.eclipse.microprofile.metrics.MetricRegistry.class).get());
+ } catch (final Exception e) {
+ // no-op
+ }
+ return new FaultToleranceMetrics() {
+ @Override
+ public void inc(final String value) {
+ // no-op
+ }
+
+ @Override
+ public void dec(final String value) {
+ // no-op
+ }
+ };
+ }
+}
+
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryBean.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
similarity index 61%
rename from safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryBean.java
rename to safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
index fcadf03..9bdf74d 100644
--- a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryBean.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/metrics/MicroprofileMetricsImpl.java
@@ -16,23 +16,27 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.safeguard.impl.metrics;
-package org.apache.safeguard.retry.test;
+import javax.enterprise.inject.Vetoed;
-import java.util.concurrent.Callable;
+import org.eclipse.microprofile.metrics.MetricRegistry;
-public class RetryBean implements Callable<String> {
- private int calls = 0;
- @Override
- public String call() throws Exception {
- calls++;
- if(calls <= 2) {
- throw new RuntimeException();
- }
- return "called";
+@Vetoed
+class MicroprofileMetricsImpl implements FaultToleranceMetrics {
+ private final MetricRegistry registry;
+
+ MicroprofileMetricsImpl(final MetricRegistry registry) {
+ this.registry = registry;
}
- public int getCalls() {
- return calls;
+ @Override
+ public void inc(final String value) {
+ registry.counter(value).inc();
+ }
+
+ @Override
+ public void dec(final String value) {
+ registry.counter(value).dec();
}
}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
similarity index 72%
rename from safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java
rename to safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
index 5f63f1e..03d7d13 100644
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/AfterRetryInterceptor.java
@@ -16,11 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.safeguard.impl.retry;
-package org.apache.safeguard.api.circuitbreaker;
+import javax.annotation.Priority;
+import javax.interceptor.Interceptor;
-public enum CircuitBreakerState {
- OPEN,
- CLOSED,
- HALF_OPEN
+import org.eclipse.microprofile.faulttolerance.Retry;
+
+@Retry
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER + 10)
+public class AfterRetryInterceptor extends BaseRetryInterceptor {
}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java
new file mode 100644
index 0000000..dcfc848
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BaseRetryInterceptor.java
@@ -0,0 +1,129 @@
+/*
+ * 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.retry;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.annotation.AnnotationFinder;
+import org.apache.safeguard.impl.config.ConfigurationMapper;
+import org.eclipse.microprofile.faulttolerance.Retry;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceException;
+
+public class BaseRetryInterceptor implements Serializable {
+ @Inject
+ private Cache cache;
+
+ @AroundInvoke
+ public Object retry(final InvocationContext context) throws Exception {
+ final Map<Method, Model> models = cache.getModels();
+ Model model = models.get(context.getMethod());
+ if (model == null) {
+ model = cache.create(context);
+ models.putIfAbsent(context.getMethod(), model);
+ }
+ for (int i = 0; i < model.maxRetries + 1; i++) {
+ try {
+ return context.proceed();
+ } catch (final RuntimeException re) {
+ if (model.abortOn(re)) {
+ throw new FaultToleranceException(re);
+ }
+ if (model.maxRetries == i) {
+ throw re;
+ }
+ if (model.retryOn(re)) {
+ Thread.sleep(model.nextPause());
+ }
+ }
+ }
+ throw new IllegalStateException("Inaccessible but needed to compile");
+ }
+
+ static class Model {
+ private final Class<? extends Throwable>[] abortOn;
+ private final Class<? extends Throwable>[] retryOn;
+ private final long maxDuration;
+ private final int maxRetries;
+ private final long delay;
+ private final long jitter;
+
+ private Model(final Retry retry) {
+ abortOn = retry.abortOn();
+ retryOn = retry.retryOn();
+ maxDuration = retry.delayUnit().getDuration().toNanos() * retry.maxDuration();
+ maxRetries = retry.maxRetries();
+ delay = retry.delayUnit().getDuration().toNanos() * retry.delay();
+ jitter = retry.jitterDelayUnit().getDuration().toNanos() * retry.jitter();
+ }
+
+ private boolean abortOn(final RuntimeException re) {
+ return matches(abortOn, re);
+ }
+
+ private boolean retryOn(final RuntimeException re) {
+ return matches(retryOn, re);
+ }
+
+ private boolean matches(final Class<? extends Throwable>[] list, final RuntimeException re) {
+ return list.length > 0 &&
+ Stream.of(list).anyMatch(it -> it.isInstance(re) || it.isInstance(re.getCause()));
+ }
+
+ private long nextPause() {
+ final ThreadLocalRandom random = ThreadLocalRandom.current();
+ return TimeUnit.NANOSECONDS.toMillis(
+ min(maxDuration, max(0, ((random.nextBoolean() ? 1 : -1) * delay) + random.nextLong(jitter))));
+ }
+ }
+
+ @ApplicationScoped
+ public static class Cache {
+ private final Map<Method, Model> models = new ConcurrentHashMap<>();
+
+ @Inject
+ private AnnotationFinder finder;
+
+ @Inject
+ private ConfigurationMapper configurationMapper;
+
+ public Map<Method, Model> getModels() {
+ return models;
+ }
+
+ public Model create(final InvocationContext context) {
+ final Retry retry = finder.findAnnotation(Retry.class, context);
+ final Retry configuredRetry = configurationMapper.map(retry, context.getMethod(), Retry.class);
+ return new Model(configuredRetry);
+ }
+ }
+}
diff --git a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
similarity index 72%
copy from safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java
copy to safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
index 5f63f1e..257c85b 100644
--- a/safeguard-api/src/main/java/org/apache/safeguard/api/circuitbreaker/CircuitBreakerState.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/BeforeRetryInterceptor.java
@@ -16,11 +16,15 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.safeguard.impl.retry;
-package org.apache.safeguard.api.circuitbreaker;
+import javax.annotation.Priority;
+import javax.interceptor.Interceptor;
-public enum CircuitBreakerState {
- OPEN,
- CLOSED,
- HALF_OPEN
+import org.eclipse.microprofile.faulttolerance.Retry;
+
+@Retry
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER)
+public class BeforeRetryInterceptor extends BaseRetryInterceptor {
}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryBuilder.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryBuilder.java
deleted file mode 100644
index b6fdba7..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryBuilder.java
+++ /dev/null
@@ -1,93 +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.safeguard.impl.retry;
-
-import net.jodah.failsafe.RetryPolicy;
-import org.apache.safeguard.api.retry.RetryBuilder;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-public class FailsafeRetryBuilder implements RetryBuilder{
- private final List<Class<? extends Throwable>> retryOn;
- private final List<Class<? extends Throwable>> abortOn;
- private final RetryPolicy retryPolicy;
- private final String name;
- private final FailsafeRetryManager failsafeRetryManager;
-
- FailsafeRetryBuilder(String name, FailsafeRetryManager failsafeRetryManager) {
- this.name = name;
- this.failsafeRetryManager = failsafeRetryManager;
- this.retryOn = new ArrayList<>();
- this.abortOn = new ArrayList<>();
- this.retryPolicy = new RetryPolicy();
- }
- @Override
- public FailsafeRetryBuilder withMaxRetries(int maxRetries) {
- retryPolicy.withMaxRetries(maxRetries);
- return this;
- }
-
- @Override
- public FailsafeRetryBuilder withDelay(Duration delay) {
- retryPolicy.withDelay(delay.toNanos(), TimeUnit.NANOSECONDS);
- return this;
- }
-
- @Override
- public FailsafeRetryBuilder withMaxDuration(Duration maxDuration) {
- retryPolicy.withMaxDuration(maxDuration.toNanos(), TimeUnit.NANOSECONDS);
- return this;
- }
-
- @Override
- public FailsafeRetryBuilder withJitter(Duration jitter) {
- retryPolicy.withJitter(jitter.toNanos(), TimeUnit.NANOSECONDS);
- return this;
- }
-
- @Override
- public FailsafeRetryBuilder withAbortOn(Class<? extends Throwable>... abortOn) {
- this.abortOn.addAll(Arrays.asList(abortOn));
- return this;
- }
-
- @Override
- public FailsafeRetryBuilder withRetryOn(Class<? extends Throwable>... retryOn) {
- this.retryOn.addAll(Arrays.asList(retryOn));
- return this;
- }
-
- @Override
- public FailsafeRetryDefinition build() {
- if(!this.abortOn.isEmpty()) {
- retryPolicy.abortOn(this.abortOn);
- }
- if(!this.retryOn.isEmpty()) {
- retryPolicy.retryOn(this.retryOn);
- }
- FailsafeRetryDefinition definition = new FailsafeRetryDefinition(retryPolicy, retryOn, abortOn);
- failsafeRetryManager.register(name, definition);
- return definition;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryDefinition.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryDefinition.java
deleted file mode 100644
index 916f204..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryDefinition.java
+++ /dev/null
@@ -1,75 +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.safeguard.impl.retry;
-
-import net.jodah.failsafe.RetryPolicy;
-import org.apache.safeguard.api.retry.RetryDefinition;
-
-import java.time.Duration;
-import java.util.Collection;
-
-public class FailsafeRetryDefinition implements RetryDefinition{
- private final RetryPolicy retryPolicy;
- private final Collection<Class<? extends Throwable>> retryExceptions;
- private final Collection<Class<? extends Throwable>> abortExceptions;
-
- FailsafeRetryDefinition(RetryPolicy retryPolicy, Collection<Class<? extends Throwable>> retryExceptions, Collection<Class<? extends Throwable>> abortExceptions) {
- this.retryPolicy = retryPolicy;
- this.retryExceptions = retryExceptions;
- this.abortExceptions = abortExceptions;
- }
-
- @Override
- public int getMaxRetries() {
- return retryPolicy.getMaxRetries();
- }
-
- @Override
- public Duration getDelay() {
- net.jodah.failsafe.util.Duration delay = retryPolicy.getDelay();
- return Duration.ofMillis(delay.toMillis());
- }
-
- @Override
- public Duration getMaxDuration() {
- net.jodah.failsafe.util.Duration maxDuration = retryPolicy.getMaxDuration();
- return Duration.ofMillis(maxDuration.toMillis());
- }
-
- @Override
- public Duration getJitter() {
- net.jodah.failsafe.util.Duration jitter = retryPolicy.getJitter();
- return Duration.ofMillis(jitter.toMillis());
- }
-
- @Override
- public Collection<Class<? extends Throwable>> getRetryExceptions() {
- return this.retryExceptions;
- }
-
- @Override
- public Collection<Class<? extends Throwable>> getAbortExceptions() {
- return abortExceptions;
- }
-
- public RetryPolicy getRetryPolicy() {
- return retryPolicy;
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryManager.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryManager.java
deleted file mode 100644
index 54d41c7..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/retry/FailsafeRetryManager.java
+++ /dev/null
@@ -1,45 +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.safeguard.impl.retry;
-
-import org.apache.safeguard.api.retry.RetryManager;
-
-import javax.enterprise.inject.Vetoed;
-import java.util.HashMap;
-import java.util.Map;
-
-@Vetoed
-public class FailsafeRetryManager implements RetryManager {
- private Map<String, FailsafeRetryDefinition> retries = new HashMap<>();
-
- @Override
- public FailsafeRetryBuilder newRetryDefinition(String name) {
- return new FailsafeRetryBuilder(name, this);
- }
-
- @Override
- public FailsafeRetryDefinition getRetryDefinition(String name) {
- return retries.get(name);
- }
-
- void register(String name, FailsafeRetryDefinition failsafeRetryDefinition) {
- this.retries.put(name, failsafeRetryDefinition);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java
new file mode 100644
index 0000000..f90f93a
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/timeout/TimeoutInterceptor.java
@@ -0,0 +1,112 @@
+/*
+ * 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.timeout;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeoutException;
+
+import javax.annotation.Priority;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.apache.safeguard.impl.annotation.AnnotationFinder;
+import org.apache.safeguard.impl.customizable.Safeguard;
+import org.eclipse.microprofile.faulttolerance.Timeout;
+import org.eclipse.microprofile.faulttolerance.exceptions.FaultToleranceDefinitionException;
+
+@Timeout
+@Interceptor
+@Priority(Interceptor.Priority.PLATFORM_AFTER + 20)
+public class TimeoutInterceptor implements Serializable {
+ @Inject
+ private Cache cache;
+
+ @Inject
+ @Safeguard
+ private Executor executor;
+
+ @AroundInvoke
+ public Object withTimeout(final InvocationContext context) throws Exception {
+ final Map<Method, Long> timeouts = cache.getTimeouts();
+ Long duration = timeouts.get(context.getMethod());
+ if (duration == null) {
+ duration = cache.create(context);
+ timeouts.putIfAbsent(context.getMethod(), duration);
+ }
+ final FutureTask<Object> task = new FutureTask<>(context::proceed);
+ executor.execute(task);
+ try {
+ return task.get(duration, NANOSECONDS);
+ } catch (final ExecutionException ee) {
+ cancel(task);
+ throw toCause(ee);
+ } catch (final TimeoutException te) {
+ cancel(task);
+ throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(te);
+ }
+ }
+
+ private void cancel(final FutureTask<Object> task) {
+ if (!task.isDone()) {
+ task.cancel(true);
+ }
+ }
+
+ private Exception toCause(final Exception te) throws Exception {
+ final Throwable cause = te.getCause();
+ if (Exception.class.isInstance(cause)) {
+ throw Exception.class.cast(cause);
+ }
+ if (Error.class.isInstance(cause)) {
+ throw Error.class.cast(cause);
+ }
+ throw te;
+ }
+
+ @ApplicationScoped
+ public static class Cache {
+ private final Map<Method, Long> timeouts = new ConcurrentHashMap<>();
+
+ @Inject
+ private AnnotationFinder finder;
+
+ public Map<Method, Long> getTimeouts() {
+ return timeouts;
+ }
+
+ public long create(final InvocationContext context) {
+ final Timeout timeout = finder.findAnnotation(Timeout.class, context);
+ if (timeout.value() < 0) {
+ throw new FaultToleranceDefinitionException("Timeout can't be < 0: " + context.getMethod());
+ }
+ return timeout.unit().getDuration().toNanos() * timeout.value();
+ }
+ }
+}
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
deleted file mode 100644
index eb3c478..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/AnnotationUtil.java
+++ /dev/null
@@ -1,50 +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.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;
-
-public final class AnnotationUtil {
- private AnnotationUtil() {
-
- }
- public static <T extends Annotation> T getAnnotation(Method method, Class<T> clazz) {
- T annotation = method.getAnnotation(clazz);
- if (annotation != null) {
- return annotation;
- }
- else {
- 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);
- }
-}
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/NamingUtil.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/NamingUtil.java
deleted file mode 100644
index 6773424..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/util/NamingUtil.java
+++ /dev/null
@@ -1,32 +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.safeguard.impl.util;
-
-import java.lang.reflect.Method;
-
-public final class NamingUtil {
- private NamingUtil() {
-
- }
-
- public static String createName(Method method) {
- return method.getDeclaringClass().getCanonicalName()+"."+method.getName();
- }
-}
diff --git a/safeguard-impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/safeguard-impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
index f938390..cb9c016 100644
--- a/safeguard-impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ b/safeguard-impl/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -16,5 +16,4 @@
# specific language governing permissions and limitations
# under the License.
#
-
-org.apache.safeguard.impl.cdi.SafeguardExtension
\ No newline at end of file
+org.apache.safeguard.impl.cdi.SafeguardExtension
diff --git a/safeguard-impl/src/main/resources/META-INF/services/org.apache.safeguard.api.config.ConfigFacade b/safeguard-impl/src/main/resources/META-INF/services/org.apache.safeguard.api.config.ConfigFacade
deleted file mode 100644
index 95d5d9b..0000000
--- a/safeguard-impl/src/main/resources/META-INF/services/org.apache.safeguard.api.config.ConfigFacade
+++ /dev/null
@@ -1,20 +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.
-#
-
-org.apache.safeguard.impl.config.ConfigFacadeFacade
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/SafeguardCDITest.java b/safeguard-impl/src/test/java/org/apache/safeguard/SafeguardCDITest.java
deleted file mode 100644
index 9a9fab6..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/SafeguardCDITest.java
+++ /dev/null
@@ -1,41 +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.safeguard;
-
-import org.apache.safeguard.impl.cdi.FailsafeExecutionManagerProvider;
-import org.apache.safeguard.impl.cdi.SafeguardExtension;
-import org.apache.safeguard.impl.cdi.SafeguardInterceptor;
-import org.jboss.arquillian.testng.Arquillian;
-import org.jboss.shrinkwrap.api.Archive;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.asset.EmptyAsset;
-import org.jboss.shrinkwrap.api.spec.JavaArchive;
-
-import javax.enterprise.inject.spi.Extension;
-
-public abstract class SafeguardCDITest extends Arquillian{
- public static Archive<?> create(Class<?>...classes) {
- return ShrinkWrap.create(JavaArchive.class)
- .addClasses(FailsafeExecutionManagerProvider.class, SafeguardInterceptor.class)
- .addClasses(classes)
- .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml")
- .addAsServiceProviderAndClasses(Extension.class, SafeguardExtension.class);
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitBean.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitBean.java
deleted file mode 100644
index cdbda86..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitBean.java
+++ /dev/null
@@ -1,32 +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.safeguard.circuitbreaker.test;
-
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-
-import javax.enterprise.context.ApplicationScoped;
-
-@ApplicationScoped
-public class CDICircuitBean {
- @CircuitBreaker(requestVolumeThreshold = 5)
- public String sayHello() {
- throw new RuntimeException("I'm failing");
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitTest.java
deleted file mode 100644
index f342e0c..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CDICircuitTest.java
+++ /dev/null
@@ -1,70 +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.safeguard.circuitbreaker.test;
-
-import org.apache.safeguard.SafeguardCDITest;
-import org.apache.safeguard.api.ExecutionManager;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-import org.apache.safeguard.impl.util.NamingUtil;
-import org.jboss.arquillian.container.test.api.Deployment;
-import org.jboss.shrinkwrap.api.Archive;
-import org.testng.annotations.Test;
-
-import javax.inject.Inject;
-import java.lang.reflect.Method;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CDICircuitTest extends SafeguardCDITest{
- @Deployment
- public static Archive<?> createDeployment() {
- return SafeguardCDITest.create(CDICircuitBean.class);
- }
-
- @Inject
- private CDICircuitBean cdiCircuitBean;
-
- @Inject
- private ExecutionManager executionManager;
-
- @Test
- public void shouldTriggerCircuitOpen() throws Exception {
- Method method = CDICircuitBean.class.getMethod("sayHello");
- String name = NamingUtil.createName(method);
-
- for(int i = 0;i<5;i++) {
- try {
- cdiCircuitBean.sayHello();
- CircuitBreaker circuitBreaker = executionManager.getCircuitBreakerManager().getCircuitBreaker(name);
- if (i < 4) {
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.CLOSED);
- }
- else {
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.OPEN);
- }
- }
- catch (Exception e){ }
- }
-
- CircuitBreaker circuitBreaker = executionManager.getCircuitBreakerManager().getCircuitBreaker(name);
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.OPEN);
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CircuitTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CircuitTest.java
deleted file mode 100644
index 00efc30..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitbreaker/test/CircuitTest.java
+++ /dev/null
@@ -1,58 +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.safeguard.circuitbreaker.test;
-
-import org.apache.safeguard.api.circuitbreaker.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-import org.apache.safeguard.impl.FailsafeExecutionManager;
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CircuitTest {
- private FailsafeExecutionManager failsafeExecutionManager;
- private static final String name = "MY_CIRCUIT_1";
-
- @BeforeTest
- public void setupForTest() {
- failsafeExecutionManager = new FailsafeExecutionManager();
- }
-
- @Test
- public void shouldUseConfiguredCircuit() {
- int failureCount = 5;
- failsafeExecutionManager.getCircuitBreakerManager().newCircuitBreaker(name)
- .withFailureCount(failureCount)
- .withFailOn(Exception.class)
- .build();
- CircuitBreaker circuitBreaker = failsafeExecutionManager.getCircuitBreakerManager().getCircuitBreaker(name);
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.CLOSED);
- for(int i = 0; i<failureCount;i++) {
- try {
- failsafeExecutionManager.execute(name, () -> {
- throw new RuntimeException("Failing");
- });
- }
- catch (Exception e) {}
- }
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.OPEN);
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDIRetryCircuitTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDIRetryCircuitTest.java
deleted file mode 100644
index e4c6c9c..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDIRetryCircuitTest.java
+++ /dev/null
@@ -1,64 +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.safeguard.circuitretry.test;
-
-import org.apache.safeguard.SafeguardCDITest;
-import org.apache.safeguard.api.ExecutionManager;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-import org.apache.safeguard.impl.util.NamingUtil;
-import org.jboss.arquillian.container.test.api.Deployment;
-import org.jboss.shrinkwrap.api.Archive;
-import org.testng.annotations.Test;
-
-import javax.inject.Inject;
-import java.lang.reflect.Method;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CDIRetryCircuitTest extends SafeguardCDITest{
-
- @Deployment
- public static Archive<?> createDeployment() {
- return SafeguardCDITest.create(CDISimpleCallable.class);
- }
-
- @Inject
- private CDISimpleCallable simpleCallable;
-
- @Inject
- private ExecutionManager executionManager;
-
- @Test
- public void shouldExecuteSevenTimes() throws Exception{
- try {
- simpleCallable.call();
- } catch (Exception e) {
- }
-
- Method method = CDISimpleCallable.class.getMethod("call");
- String name = NamingUtil.createName(method);
- CircuitBreaker circuitBreaker = executionManager.getCircuitBreakerManager().getCircuitBreaker(name);
-
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.OPEN);
- assertThat(simpleCallable.getCounter()).isEqualTo(4);
- }
-
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDISimpleCallable.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDISimpleCallable.java
deleted file mode 100644
index 3ba25a2..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/CDISimpleCallable.java
+++ /dev/null
@@ -1,43 +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.safeguard.circuitretry.test;
-
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Retry;
-
-import javax.enterprise.context.ApplicationScoped;
-import java.util.concurrent.Callable;
-
-@ApplicationScoped
-public class CDISimpleCallable implements Callable<Object> {
- private int counter = 0;
-
- @Override
- @Retry(maxRetries = 7, retryOn = RuntimeException.class)
- @CircuitBreaker(successThreshold = 2, failureRatio = 0.75, requestVolumeThreshold = 4, delay = 50000)
- public Object call() throws Exception {
- counter++;
- throw new RuntimeException("Invalid state");
- }
-
- public int getCounter() {
- return counter;
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/RetryCircuitTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/RetryCircuitTest.java
deleted file mode 100644
index 5c6b5e0..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/circuitretry/test/RetryCircuitTest.java
+++ /dev/null
@@ -1,69 +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.safeguard.circuitretry.test;
-
-import org.apache.safeguard.api.circuitbreaker.CircuitBreaker;
-import org.apache.safeguard.api.circuitbreaker.CircuitBreakerState;
-import org.apache.safeguard.impl.FailsafeExecutionManager;
-import org.testng.annotations.Test;
-
-import java.time.Duration;
-import java.util.concurrent.Callable;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RetryCircuitTest {
- @Test
- public void shouldExecuteBothRetryAndCircuitBreaker() {
- String name = "retryCircuitTest";
- FailsafeExecutionManager failsafeExecutionManager = new FailsafeExecutionManager();
- int maxRetries = 7;
- failsafeExecutionManager.getRetryManager()
- .newRetryDefinition(name)
- .withMaxRetries(maxRetries)
- .withRetryOn(RuntimeException.class).build();
- failsafeExecutionManager.getCircuitBreakerManager()
- .newCircuitBreaker(name)
- .withSuccessCount(2)
- .withFailures(3, 4)
- .withDelay(Duration.ofMillis(5000))
- .withFailOn(RuntimeException.class)
- .build();
- CircuitBreaker circuitBreaker = failsafeExecutionManager.getCircuitBreakerManager().getCircuitBreaker(name);
-
- SimpleCallable simpleCallable = new SimpleCallable();
- try {
- failsafeExecutionManager.execute(name, simpleCallable);
- }catch (RuntimeException e) {
- }
- assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreakerState.OPEN);
- assertThat(simpleCallable.counter).isEqualTo(4);
- }
-
- private static class SimpleCallable implements Callable<Object> {
- private int counter = 0;
-
- @Override
- public Object call() throws Exception {
- counter++;
- throw new RuntimeException("Invalid state");
- }
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java
new file mode 100644
index 0000000..18193d1
--- /dev/null
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java
@@ -0,0 +1,39 @@
+/*
+ * 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.ft.tck;
+
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+
+public class ArchiveAppender implements ApplicationArchiveProcessor {
+
+ @Override
+ public void process(final Archive<?> archive, final TestClass testClass) {
+ archive.as(WebArchive.class)
+ .addAsLibrary(ShrinkWrap.create(JavaArchive.class, "safeguard-impl.jar")
+ .addPackages(true, "org.apache.safeguard")
+ .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"));
+ }
+}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java
new file mode 100644
index 0000000..d7d1c0c
--- /dev/null
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/IDERunner.java
@@ -0,0 +1,6 @@
+package org.apache.safeguard.ft.tck;
+
+import org.eclipse.microprofile.fault.tolerance.tck.circuitbreaker.CircuitBreakerConfigOnMethodTest;
+
+public class IDERunner extends CircuitBreakerConfigOnMethodTest {
+}
diff --git a/safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java
similarity index 94%
rename from safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java
rename to safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java
index 6d57660..858dc0e 100644
--- a/safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/ft/tck/SafeguardTCKExtension.java
@@ -24,7 +24,7 @@
public class SafeguardTCKExtension implements LoadableExtension {
@Override
- public void register(ExtensionBuilder extensionBuilder) {
+ public void register(final ExtensionBuilder extensionBuilder) {
extensionBuilder.service(ApplicationArchiveProcessor.class, ArchiveAppender.class);
}
}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlanTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlanTest.java
deleted file mode 100644
index 1484f99..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlanTest.java
+++ /dev/null
@@ -1,50 +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.safeguard.impl.executionPlans;
-
-import org.testng.annotations.Test;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class AsyncOnlyExecutionPlanTest {
-
- @Test
- public void shouldExecuteAsncWithoutTimeout() {
- AsyncOnlyExecutionPlan asyncOnlyExecutionPlan = new AsyncOnlyExecutionPlan(Executors.newFixedThreadPool(2));
- MyCallable callable = new MyCallable();
- asyncOnlyExecutionPlan.execute(callable, null);
- assertThat(callable.calledThread).isNotEqualTo(Thread.currentThread().getName());
- }
-
- private static class MyCallable implements Callable<Object> {
-
- private String calledThread;
-
- @Override
- public Object call() throws Exception {
- this.calledThread = Thread.currentThread().getName();
- return "";
- }
- }
-
-}
\ No newline at end of file
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlanTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlanTest.java
deleted file mode 100644
index 9bf2ffe..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlanTest.java
+++ /dev/null
@@ -1,68 +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.safeguard.impl.executionPlans;
-
-import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException;
-import org.testng.annotations.Test;
-
-import java.time.Duration;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class AsyncTimeoutExecutionPlanTest {
- @Test
- public void shouldExecuteSimpleCallable() {
- AsyncTimeoutExecutionPlan asyncTimeoutExecutionPlan = new AsyncTimeoutExecutionPlan(Duration.ofMillis(1000), Executors.newSingleThreadExecutor());
- DelayedCaller callable = new DelayedCaller(200);
-
- asyncTimeoutExecutionPlan.execute(callable, null);
-
- String myThreadName = Thread.currentThread().getName();
- assertThat(callable.executedThread).isNotEqualTo(myThreadName);
- }
-
- @Test
- public void shouldThrowTimeoutWhenDelayHit() {
- AsyncTimeoutExecutionPlan asyncTimeoutExecutionPlan = new AsyncTimeoutExecutionPlan(Duration.ofMillis(100), Executors.newSingleThreadExecutor());
- DelayedCaller callable = new DelayedCaller(200);
-
- assertThatThrownBy(() -> asyncTimeoutExecutionPlan.execute(callable, null)).isInstanceOf(TimeoutException.class);
- }
-
- private static class DelayedCaller implements Callable<Object> {
-
- private final long delay;
- private String executedThread;
-
- public DelayedCaller(long delay) {
- this.delay = delay;
- }
-
- @Override
- public Object call() throws Exception {
- this.executedThread = Thread.currentThread().getName();
- Thread.sleep(delay);
- return new Object();
- }
- }
-}
\ No newline at end of file
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlanTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlanTest.java
deleted file mode 100644
index 016cdef..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlanTest.java
+++ /dev/null
@@ -1,33 +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.safeguard.impl.executionPlans;
-
-import org.testng.annotations.Test;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class SyncFailsafeExecutionPlanTest {
- @Test
- public void shouldThrowExceptionWithInvalidConfig() {
- assertThatThrownBy(() -> new SyncFailsafeExecutionPlan(null, null, null))
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("For non-async invocations, must have at least one of RetryDefintion or CircuitBreaker defined");
- }
-}
\ No newline at end of file
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryBean.java b/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryBean.java
deleted file mode 100644
index 3d69ab0..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryBean.java
+++ /dev/null
@@ -1,41 +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.safeguard.retry.test;
-
-import org.eclipse.microprofile.faulttolerance.Retry;
-
-import javax.enterprise.context.ApplicationScoped;
-
-@ApplicationScoped
-public class CDIRetryBean {
- private int calls = 0;
- @Retry
- public String doCall() {
- calls++;
- if(calls <= 2) {
- throw new RuntimeException();
- }
- return "retried";
- }
-
- public int getCalls() {
- return calls;
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryTest.java
deleted file mode 100644
index 73dbf9e..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/CDIRetryTest.java
+++ /dev/null
@@ -1,54 +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.safeguard.retry.test;
-
-import org.apache.safeguard.SafeguardCDITest;
-import org.apache.safeguard.impl.cdi.FailsafeExecutionManagerProvider;
-import org.apache.safeguard.impl.cdi.SafeguardExtension;
-import org.apache.safeguard.impl.cdi.SafeguardInterceptor;
-import org.jboss.arquillian.container.test.api.Deployment;
-import org.jboss.arquillian.testng.Arquillian;
-import org.jboss.shrinkwrap.api.Archive;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.asset.EmptyAsset;
-import org.jboss.shrinkwrap.api.spec.JavaArchive;
-import org.testng.annotations.Test;
-
-import javax.enterprise.inject.spi.Extension;
-import javax.inject.Inject;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CDIRetryTest extends SafeguardCDITest {
- @Deployment
- public static Archive<?> create() {
- return SafeguardCDITest.create(CDIRetryBean.class);
- }
-
- @Inject
- private CDIRetryBean cdiRetryBean;
-
- @Test
- public void shouldExecuteThreeTimesWithAnnotations() {
- cdiRetryBean.doCall();
-
- assertThat(cdiRetryBean.getCalls()).isEqualTo(3);
- }
-}
diff --git a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryTest.java b/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryTest.java
deleted file mode 100644
index 094c860..0000000
--- a/safeguard-impl/src/test/java/org/apache/safeguard/retry/test/RetryTest.java
+++ /dev/null
@@ -1,49 +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.safeguard.retry.test;
-
-import org.apache.safeguard.impl.FailsafeExecutionManager;
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RetryTest {
- private FailsafeExecutionManager failsafeExecutionManager;
- private static final String name = "GUARDED_RETRIES";
-
- @BeforeTest
- public void setupForTest() {
- failsafeExecutionManager = new FailsafeExecutionManager();
- }
-
- @Test
- public void testRetryWithManualBuild() {
- int expectedCalls = 3;
- failsafeExecutionManager.getRetryManager().newRetryDefinition(name)
- .withMaxRetries(expectedCalls)
- .build();
- RetryBean retryBean = new RetryBean();
-
- failsafeExecutionManager.execute(name, retryBean);
-
- assertThat(retryBean.getCalls()).isEqualTo(expectedCalls);
- }
-}
diff --git a/safeguard-tck-tests/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/safeguard-impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
similarity index 99%
rename from safeguard-tck-tests/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
rename to safeguard-impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
index 65b7838..577a99e 100644
--- a/safeguard-tck-tests/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
+++ b/safeguard-impl/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -16,5 +16,4 @@
# specific language governing permissions and limitations
# under the License.
#
-
-org.apache.safeguard.ft.tck.SafeguardTCKExtension
\ No newline at end of file
+org.apache.safeguard.ft.tck.SafeguardTCKExtension
diff --git a/safeguard-tck-tests/pom.xml b/safeguard-tck-tests/pom.xml
deleted file mode 100644
index c5e8c42..0000000
--- a/safeguard-tck-tests/pom.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ 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">
- <parent>
- <artifactId>safeguard-parent</artifactId>
- <groupId>org.apache.geronimo.safeguard</groupId>
- <version>1.1-SNAPSHOT</version>
- </parent>
- <name>Apache Safeguard :: MicroProfile TCK Tests</name>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>safeguard-tck-tests</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>org.eclipse.microprofile.fault-tolerance</groupId>
- <artifactId>microprofile-fault-tolerance-tck</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.safeguard</groupId>
- <artifactId>safeguard-impl</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jcdi_2.0_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-atinject_1.0_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-annotation_1.3_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-interceptor_1.2_spec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.config</groupId>
- <artifactId>geronimo-config-impl</artifactId>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.20</version>
- <configuration>
- <dependenciesToScan>
- <dependency>org.eclipse.microprofile.fault-tolerance:microprofile-fault-tolerance-tck</dependency>
- </dependenciesToScan>
- <excludes>
- <exclude>org.eclipse.microprofile.fault.tolerance.tck.ConfigTest</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
\ No newline at end of file
diff --git a/safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java b/safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java
deleted file mode 100644
index 28b2f58..0000000
--- a/safeguard-tck-tests/src/test/java/org/apache/safeguard/ft/tck/ArchiveAppender.java
+++ /dev/null
@@ -1,49 +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.safeguard.ft.tck;
-
-import org.apache.safeguard.api.SafeguardEnabled;
-import org.apache.safeguard.api.config.ConfigFacade;
-import org.apache.safeguard.impl.cdi.FailsafeExecutionManagerProvider;
-import org.apache.safeguard.impl.cdi.SafeguardExtension;
-import org.apache.safeguard.impl.cdi.SafeguardInterceptor;
-import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
-import org.jboss.arquillian.test.spi.TestClass;
-import org.jboss.shrinkwrap.api.Archive;
-import org.jboss.shrinkwrap.api.ShrinkWrap;
-import org.jboss.shrinkwrap.api.asset.StringAsset;
-import org.jboss.shrinkwrap.api.spec.JavaArchive;
-import org.jboss.shrinkwrap.api.spec.WebArchive;
-
-import javax.enterprise.inject.spi.Extension;
-
-public class ArchiveAppender implements ApplicationArchiveProcessor {
- private static final StringAsset BEANS_XML = new StringAsset("<beans version=\"1.1\" bean-discovery-mode=\"all\"/>");
-
- @Override
- public void process(Archive<?> archive, TestClass testClass) {
- ConfigFacade.setInstance(null);
- JavaArchive jar = ShrinkWrap.create(JavaArchive.class, "safeguard.jar")
- .addClasses(SafeguardEnabled.class, SafeguardExtension.class, FailsafeExecutionManagerProvider.class, SafeguardInterceptor.class)
- .addAsServiceProvider(Extension.class, SafeguardExtension.class)
- .addAsManifestResource(BEANS_XML, "beans.xml");
- archive.as(WebArchive.class).addAsLibrary(jar);
- }
-}