You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jo...@apache.org on 2017/09/13 11:35:49 UTC
geronimo-safeguard git commit: GERONIMO-6582 - Adding more execution
plans.
Repository: geronimo-safeguard
Updated Branches:
refs/heads/master cf5a00023 -> 7c93e2983
GERONIMO-6582 - Adding more execution plans.
Project: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/repo
Commit: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/commit/7c93e298
Tree: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/tree/7c93e298
Diff: http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/diff/7c93e298
Branch: refs/heads/master
Commit: 7c93e298388dec63bd1835d71c703fb3507fa332
Parents: cf5a000
Author: John D. Ament <jo...@apache.org>
Authored: Wed Sep 13 07:35:45 2017 -0400
Committer: John D. Ament <jo...@apache.org>
Committed: Wed Sep 13 07:35:45 2017 -0400
----------------------------------------------------------------------
.../apache/safeguard/api/ExecutionManager.java | 33 +++++
.../safeguard/exception/AsyncException.java | 26 ++++
.../apache/safeguard/impl/ExecutionPlan.java | 61 ---------
.../safeguard/impl/ExecutionPlanFactory.java | 90 -------------
.../impl/FailsafeExecutionManager.java | 43 +++----
.../impl/MicroprofileAnnotationMapper.java | 60 ---------
.../AsyncFailsafeExecutionPlan.java | 59 +++++++++
.../executionPlans/AsyncOnlyExecutionPlan.java | 45 +++++++
.../AsyncTimeoutExecutionPlan.java | 48 +++++++
.../impl/executionPlans/ExecutionPlan.java | 26 ++++
.../executionPlans/ExecutionPlanFactory.java | 125 +++++++++++++++++++
.../MicroprofileAnnotationMapper.java | 60 +++++++++
.../SyncFailsafeExecutionPlan.java | 66 ++++++++++
.../AsyncOnlyExecutionPlanTest.java | 50 ++++++++
.../AsyncTimeoutExecutionPlanTest.java | 68 ++++++++++
.../SyncFailsafeExecutionPlanTest.java | 33 +++++
16 files changed, 655 insertions(+), 238 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-api/src/main/java/org/apache/safeguard/api/ExecutionManager.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..86a69c8
--- /dev/null
+++ b/safeguard-api/src/main/java/org/apache/safeguard/api/ExecutionManager.java
@@ -0,0 +1,33 @@
+/*
+ * 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.circuitbreaker.CircuitBreakerManager;
+import org.apache.safeguard.api.retry.RetryManager;
+
+import java.util.concurrent.Callable;
+
+public interface ExecutionManager {
+ <T> T execute(String name, Callable<T> callable);
+
+ CircuitBreakerManager getCircuitBreakerManager();
+
+ RetryManager getRetryManager();
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-api/src/main/java/org/apache/safeguard/exception/AsyncException.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..08be3a8
--- /dev/null
+++ b/safeguard-api/src/main/java/org/apache/safeguard/exception/AsyncException.java
@@ -0,0 +1,26 @@
+/*
+ * 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 RuntimeException {
+ public AsyncException(Exception e) {
+ super(e);
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlan.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlan.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlan.java
deleted file mode 100644
index 0fc0e88..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlan.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.impl;
-
-import net.jodah.failsafe.Failsafe;
-import net.jodah.failsafe.SyncFailsafe;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
-
-import java.time.Duration;
-import java.util.concurrent.Callable;
-
-class ExecutionPlan {
- private final Duration timeout;
- private final boolean isAsynchronous;
- private final FailsafeRetryDefinition retryDefinition;
- private final FailsafeCircuitBreaker failsafeCircuitBreaker;
-
- public ExecutionPlan(Duration timeout, boolean isAsynchronous, FailsafeRetryDefinition retryDefinition, FailsafeCircuitBreaker failsafeCircuitBreaker) {
- this.timeout = timeout;
- this.isAsynchronous = isAsynchronous;
- this.retryDefinition = retryDefinition;
- this.failsafeCircuitBreaker = failsafeCircuitBreaker;
- if(retryDefinition == null && failsafeCircuitBreaker == null && !isAsynchronous) {
- throw new IllegalStateException("For non-async invocations, must have at least one of RetryDefintion or CircuitBreaker defined");
- }
- }
-
- public <T> T execute(Callable<T> callable) {
- SyncFailsafe<?> syncFailsafe;
- 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());
- }
- }
- return syncFailsafe.get(callable);
- }
-}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlanFactory.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlanFactory.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlanFactory.java
deleted file mode 100644
index 84587d3..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/ExecutionPlanFactory.java
+++ /dev/null
@@ -1,90 +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.impl.circuitbreaker.FailsafeCircuitBreaker;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerBuilder;
-import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerManager;
-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.AnnotationUtil;
-import org.apache.safeguard.impl.util.NamingUtil;
-import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Retry;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.apache.safeguard.impl.MicroprofileAnnotationMapper.mapCircuitBreaker;
-import static org.apache.safeguard.impl.MicroprofileAnnotationMapper.mapRetry;
-
-public class ExecutionPlanFactory {
- private final FailsafeCircuitBreakerManager circuitBreakerManager;
- private final FailsafeRetryManager retryManager;
- private Map<String, ExecutionPlan> executionPlanMap = new HashMap<>();
-
- public ExecutionPlanFactory(FailsafeCircuitBreakerManager circuitBreakerManager, FailsafeRetryManager retryManager) {
- this.circuitBreakerManager = circuitBreakerManager;
- this.retryManager = retryManager;
- }
-
- ExecutionPlan locateExecutionPlan(String name) {
- return executionPlanMap.computeIfAbsent(name, name1 -> {
- FailsafeCircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(name1);
- FailsafeRetryDefinition retryDefinition = retryManager.getRetryDefinition(name1);
- return new ExecutionPlan(null, false, retryDefinition, circuitBreaker);
- });
- }
-
- ExecutionPlan locateExecutionPlan(Method method) {
- final String name = NamingUtil.createName(method);
- return executionPlanMap.computeIfAbsent(name, name1 -> {
- FailsafeCircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(name1);
- if(circuitBreaker == null) {
- circuitBreaker = createCBDefinition(name, method);
- }
- FailsafeRetryDefinition retryDefinition = retryManager.getRetryDefinition(name1);
- if(retryDefinition == null) {
- retryDefinition =createDefinition(name, method);
- }
- return new ExecutionPlan(null, false, retryDefinition, circuitBreaker);
- });
- }
-
- private FailsafeRetryDefinition createDefinition(String name, Method method) {
- Retry retry = AnnotationUtil.getAnnotation(method, Retry.class);
- if (retry == null) {
- return null;
- }
- FailsafeRetryBuilder retryBuilder = retryManager.newRetryDefinition(name);
- return mapRetry(retry, retryBuilder);
- }
-
- private FailsafeCircuitBreaker createCBDefinition(String name, Method method) {
- CircuitBreaker circuitBreaker = AnnotationUtil.getAnnotation(method, CircuitBreaker.class);
- if (circuitBreaker == null) {
- return null;
- }
- FailsafeCircuitBreakerBuilder circuitBreakerBuilder = this.circuitBreakerManager.newCircuitBreaker(name);
- return new FailsafeCircuitBreaker(mapCircuitBreaker(circuitBreaker, circuitBreakerBuilder));
- }
-}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java
----------------------------------------------------------------------
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
index 67cb4a1..35d3fa9 100644
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/FailsafeExecutionManager.java
@@ -19,16 +19,19 @@
package org.apache.safeguard.impl;
+import org.apache.safeguard.api.ExecutionManager;
import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerManager;
+import org.apache.safeguard.impl.executionPlans.ExecutionPlanFactory;
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;
@Vetoed
-public class FailsafeExecutionManager {
+public class FailsafeExecutionManager implements ExecutionManager {
private FailsafeCircuitBreakerManager circuitBreakerManager;
private FailsafeRetryManager retryManager;
private ExecutionPlanFactory executionPlanFactory;
@@ -42,47 +45,33 @@ public class FailsafeExecutionManager {
public Object execute(InvocationContext invocationContext) {
Method method = invocationContext.getMethod();
return executionPlanFactory.locateExecutionPlan(method).execute(invocationContext::proceed);
-// String name = NamingUtil.createName(method);
-// FailsafeRetryDefinition failsafeRetryDefinition = retryManager.getRetryDefinition(name);
-// if (failsafeRetryDefinition == null) {
-// failsafeRetryDefinition = createDefinition(name, method);
-// }
-// return Failsafe.with(failsafeRetryDefinition.getRetryPolicy()).get(invocationContext::proceed);
}
+ @Override
public <T> T execute(String name, Callable<T> callable) {
- return executionPlanFactory.locateExecutionPlan(name).execute(callable);
-// FailsafeRetryDefinition failsafeRetryDefinition = retryManager.getRetryDefinition(name);
-// return Failsafe.with(failsafeRetryDefinition.getRetryPolicy()).get(callable);
+ return executionPlanFactory.locateExecutionPlan(name, null, false).execute(callable);
+ }
+
+ public <T> T executeAsync(String name, Callable<T> callable) {
+ return executionPlanFactory.locateExecutionPlan(name, null, true).execute(callable);
+ }
+
+ public <T> T executeAsync(String name, Callable<T> callable, Duration timeout) {
+ return executionPlanFactory.locateExecutionPlan(name, timeout, true).execute(callable);
}
public ExecutionPlanFactory getExecutionPlanFactory() {
return executionPlanFactory;
}
+ @Override
public FailsafeCircuitBreakerManager getCircuitBreakerManager() {
return circuitBreakerManager;
}
+ @Override
public FailsafeRetryManager getRetryManager() {
return retryManager;
}
- // private FailsafeRetryDefinition createDefinition(String name, Method method) {
-// Retry retry = AnnotationUtil.getAnnotation(method, Retry.class);
-// if(retry == null) {
-// return null;
-// }
-// FailsafeRetryBuilder retryBuilder = retryManager.newRetryDefinition(name);
-// return mapRetry(retry, retryBuilder);
-// }
-
-// private FailsafeCircuitBreakerDefinition createCBDefinition(String name, Method method) {
-// CircuitBreaker circuitBreaker = AnnotationUtil.getAnnotation(method, CircuitBreaker.class);
-// if (circuitBreaker == null) {
-// return null;
-// }
-// FailsafeCircuitBreakerBuilder circuitBreakerBuilder = this.circuitBreakerManager.newCircuitBreaker(name);
-// return mapCircuitBreaker(circuitBreaker, circuitBreakerBuilder);
-// }
}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/MicroprofileAnnotationMapper.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/MicroprofileAnnotationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/MicroprofileAnnotationMapper.java
deleted file mode 100644
index 7a8f111..0000000
--- a/safeguard-impl/src/main/java/org/apache/safeguard/impl/MicroprofileAnnotationMapper.java
+++ /dev/null
@@ -1,60 +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.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 java.time.Duration;
-
-class MicroprofileAnnotationMapper {
- static FailsafeRetryDefinition mapRetry(Retry retry, FailsafeRetryBuilder retryBuilder) {
- retryBuilder.withMaxRetries(retry.maxRetries())
- .withRetryOn(retry.retryOn())
- .withAbortOn(retry.abortOn());
- if (retry.delay() > 0L) {
- retryBuilder.withDelay(Duration.of(retry.delay(), retry.delayUnit()));
- }
- if (retry.jitter() > 0L) {
- retryBuilder.withJitter(Duration.of(retry.jitter(), retry.jitterDelayUnit()));
- }
- if (retry.maxDuration() > 0L) {
- retryBuilder.withMaxDuration(Duration.of(retry.maxDuration(), retry.durationUnit()));
- }
- return retryBuilder.build();
- }
-
- static FailsafeCircuitBreakerDefinition mapCircuitBreaker(CircuitBreaker circuitBreaker,
- FailsafeCircuitBreakerBuilder builder) {
- int failureCount = (int) (circuitBreaker.failureRatio() * circuitBreaker.requestVolumeThreshold());
- FailsafeCircuitBreakerBuilder failsafeCircuitBreakerBuilder = builder
- .withFailOn(circuitBreaker.failOn())
- .withDelay(Duration.of(circuitBreaker.delay(), circuitBreaker.delayUnit()))
- .withSuccessCount(circuitBreaker.successThreshold());
- if (failureCount > 0) {
- failsafeCircuitBreakerBuilder.withFailures(failureCount, circuitBreaker.requestVolumeThreshold());
- }
- return failsafeCircuitBreakerBuilder.build();
- }
-}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncFailsafeExecutionPlan.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..589883a
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncFailsafeExecutionPlan.java
@@ -0,0 +1,59 @@
+/*
+ * 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 org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
+import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
+
+import java.time.Duration;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class AsyncFailsafeExecutionPlan extends SyncFailsafeExecutionPlan {
+ private final ScheduledExecutorService executorService;
+ private final Duration timeout;
+
+ public AsyncFailsafeExecutionPlan(FailsafeRetryDefinition retryDefinition,
+ FailsafeCircuitBreaker failsafeCircuitBreaker,
+ ScheduledExecutorService executorService,
+ Duration timeout) {
+ super(retryDefinition, failsafeCircuitBreaker);
+ this.executorService = executorService;
+ this.timeout = timeout;
+ }
+
+ @Override
+ public <T> T execute(Callable<T> callable) {
+ AsyncFailsafe<?> asyncFailsafe = getSyncFailsafe().with(executorService);
+ try {
+ if (this.timeout == null) {
+ return asyncFailsafe.get(callable).get();
+ } else {
+ return asyncFailsafe.get(callable).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
+ }
+ } catch (TimeoutException | InterruptedException | ExecutionException e) {
+ throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(e);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlan.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..9af94c2
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlan.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.safeguard.impl.executionPlans;
+
+import org.apache.safeguard.exception.AsyncException;
+
+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) {
+ Future<T> submitted = executorService.submit(callable);
+ try {
+ return submitted.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new AsyncException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlan.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..849f7c4
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlan.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.safeguard.impl.executionPlans;
+
+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) {
+ Future<T> future = executorService.submit(callable);
+ try {
+ return future.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ throw new org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlan.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..01c3271
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlan.java
@@ -0,0 +1,26 @@
+/*
+ * 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 java.util.concurrent.Callable;
+
+public interface ExecutionPlan {
+ <T> T execute(Callable<T> callable);
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlanFactory.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..4a5086e
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/ExecutionPlanFactory.java
@@ -0,0 +1,125 @@
+/*
+ * 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.circuitbreaker.FailsafeCircuitBreaker;
+import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerBuilder;
+import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreakerManager;
+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.AnnotationUtil;
+import org.apache.safeguard.impl.util.NamingUtil;
+import org.eclipse.microprofile.faulttolerance.Asynchronous;
+import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
+import org.eclipse.microprofile.faulttolerance.Retry;
+import org.eclipse.microprofile.faulttolerance.Timeout;
+
+import java.lang.reflect.Method;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.safeguard.impl.executionPlans.MicroprofileAnnotationMapper.mapCircuitBreaker;
+import static org.apache.safeguard.impl.executionPlans.MicroprofileAnnotationMapper.mapRetry;
+
+public class ExecutionPlanFactory {
+ private final FailsafeCircuitBreakerManager circuitBreakerManager;
+ private final FailsafeRetryManager retryManager;
+ private Map<String, ExecutionPlan> executionPlanMap = new HashMap<>();
+
+ public ExecutionPlanFactory(FailsafeCircuitBreakerManager circuitBreakerManager, FailsafeRetryManager retryManager) {
+ this.circuitBreakerManager = circuitBreakerManager;
+ this.retryManager = retryManager;
+ }
+
+ 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);
+ }
+ });
+ }
+
+ public ExecutionPlan locateExecutionPlan(Method method) {
+ final String name = NamingUtil.createName(method);
+ return executionPlanMap.computeIfAbsent(name, key -> {
+ FailsafeCircuitBreaker circuitBreaker = circuitBreakerManager.getCircuitBreaker(key);
+ if (circuitBreaker == null) {
+ circuitBreaker = createCBDefinition(name, method);
+ }
+ FailsafeRetryDefinition retryDefinition = retryManager.getRetryDefinition(key);
+ if (retryDefinition == null) {
+ retryDefinition = createDefinition(name, method);
+ }
+ boolean isAsync = isAsync(method);
+ Duration timeout = readTimeout(method);
+ if(circuitBreaker == null && retryDefinition == null && isAsync) {
+ if(timeout == null) {
+ return new AsyncOnlyExecutionPlan(null);
+ }
+ else {
+ return new AsyncTimeoutExecutionPlan(timeout, null);
+ }
+ }
+ else {
+ if (isAsync) {
+ return new AsyncFailsafeExecutionPlan(retryDefinition, circuitBreaker, null, timeout);
+ } else {
+ return new SyncFailsafeExecutionPlan(retryDefinition, circuitBreaker);
+ }
+ }
+ });
+ }
+
+ private FailsafeRetryDefinition createDefinition(String name, Method method) {
+ Retry retry = AnnotationUtil.getAnnotation(method, Retry.class);
+ if (retry == null) {
+ return null;
+ }
+ FailsafeRetryBuilder retryBuilder = retryManager.newRetryDefinition(name);
+ return mapRetry(retry, retryBuilder);
+ }
+
+ private FailsafeCircuitBreaker createCBDefinition(String name, Method method) {
+ CircuitBreaker circuitBreaker = AnnotationUtil.getAnnotation(method, CircuitBreaker.class);
+ if (circuitBreaker == null) {
+ return null;
+ }
+ FailsafeCircuitBreakerBuilder circuitBreakerBuilder = this.circuitBreakerManager.newCircuitBreaker(name);
+ return new FailsafeCircuitBreaker(mapCircuitBreaker(circuitBreaker, circuitBreakerBuilder));
+ }
+
+ private boolean isAsync(Method method) {
+ return AnnotationUtil.getAnnotation(method, Asynchronous.class) != null;
+ }
+
+ private Duration readTimeout(Method method) {
+ Timeout timeout = AnnotationUtil.getAnnotation(method, Timeout.class);
+ if(timeout == null) {
+ return null;
+ }
+ return Duration.of(timeout.value(), timeout.unit());
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
----------------------------------------------------------------------
diff --git a/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
new file mode 100644
index 0000000..befd5e5
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/MicroprofileAnnotationMapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.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 java.time.Duration;
+
+class MicroprofileAnnotationMapper {
+ static FailsafeRetryDefinition mapRetry(Retry retry, FailsafeRetryBuilder retryBuilder) {
+ retryBuilder.withMaxRetries(retry.maxRetries())
+ .withRetryOn(retry.retryOn())
+ .withAbortOn(retry.abortOn());
+ if (retry.delay() > 0L) {
+ retryBuilder.withDelay(Duration.of(retry.delay(), retry.delayUnit()));
+ }
+ if (retry.jitter() > 0L) {
+ retryBuilder.withJitter(Duration.of(retry.jitter(), retry.jitterDelayUnit()));
+ }
+ if (retry.maxDuration() > 0L) {
+ retryBuilder.withMaxDuration(Duration.of(retry.maxDuration(), retry.durationUnit()));
+ }
+ return retryBuilder.build();
+ }
+
+ static FailsafeCircuitBreakerDefinition mapCircuitBreaker(CircuitBreaker circuitBreaker,
+ FailsafeCircuitBreakerBuilder builder) {
+ int failureCount = (int) (circuitBreaker.failureRatio() * circuitBreaker.requestVolumeThreshold());
+ FailsafeCircuitBreakerBuilder failsafeCircuitBreakerBuilder = builder
+ .withFailOn(circuitBreaker.failOn())
+ .withDelay(Duration.of(circuitBreaker.delay(), circuitBreaker.delayUnit()))
+ .withSuccessCount(circuitBreaker.successThreshold());
+ if (failureCount > 0) {
+ failsafeCircuitBreakerBuilder.withFailures(failureCount, circuitBreaker.requestVolumeThreshold());
+ }
+ return failsafeCircuitBreakerBuilder.build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlan.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..613ceab
--- /dev/null
+++ b/safeguard-impl/src/main/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlan.java
@@ -0,0 +1,66 @@
+/*
+ * 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.Failsafe;
+import net.jodah.failsafe.SyncFailsafe;
+import org.apache.safeguard.impl.circuitbreaker.FailsafeCircuitBreaker;
+import org.apache.safeguard.impl.retry.FailsafeRetryDefinition;
+
+import java.util.concurrent.Callable;
+
+public class SyncFailsafeExecutionPlan implements ExecutionPlan {
+ private final FailsafeRetryDefinition retryDefinition;
+ private final FailsafeCircuitBreaker failsafeCircuitBreaker;
+
+ SyncFailsafeExecutionPlan(FailsafeRetryDefinition retryDefinition, FailsafeCircuitBreaker failsafeCircuitBreaker) {
+ this.retryDefinition = retryDefinition;
+ this.failsafeCircuitBreaker = failsafeCircuitBreaker;
+ 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) {
+ SyncFailsafe<?> syncFailsafe = getSyncFailsafe();
+ return syncFailsafe.get(callable);
+ }
+
+ SyncFailsafe<?> getSyncFailsafe() {
+ SyncFailsafe<?> syncFailsafe;
+ 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());
+ }
+ }
+ return syncFailsafe;
+ }
+}
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlanTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..4c52faf
--- /dev/null
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncOnlyExecutionPlanTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.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);
+ 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
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlanTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..b45727a
--- /dev/null
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/AsyncTimeoutExecutionPlanTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.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);
+
+ 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)).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
http://git-wip-us.apache.org/repos/asf/geronimo-safeguard/blob/7c93e298/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlanTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..66876e3
--- /dev/null
+++ b/safeguard-impl/src/test/java/org/apache/safeguard/impl/executionPlans/SyncFailsafeExecutionPlanTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessage("For non-async invocations, must have at least one of RetryDefintion or CircuitBreaker defined");
+ }
+}
\ No newline at end of file