org.springframework.retry.policy.ExceptionClassifierRetryPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-retry Show documentation
Show all versions of spring-retry Show documentation
Spring Retry provides an abstraction around retrying failed operations, with an
emphasis on declarative control of the process and policy-based behaviour that is
easy to extend and customize. For instance, you can configure a plain POJO
operation to retry if it fails, based on the type of exception, and with a fixed
or exponential backoff.
/*
* Copyright 2006-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.retry.policy;
import java.util.HashMap;
import java.util.Map;
import org.springframework.classify.Classifier;
import org.springframework.classify.ClassifierSupport;
import org.springframework.classify.SubclassClassifier;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.context.RetryContextSupport;
import org.springframework.util.Assert;
/**
* A {@link RetryPolicy} that dynamically adapts to one of a set of injected policies
* according to the value of the latest exception.
*
* @author Dave Syer
*
*/
@SuppressWarnings("serial")
public class ExceptionClassifierRetryPolicy implements RetryPolicy {
private Classifier exceptionClassifier = new ClassifierSupport<>(new NeverRetryPolicy());
/**
* Setter for policy map used to create a classifier. Either this property or the
* exception classifier directly should be set, but not both.
* @param policyMap a map of Throwable class to {@link RetryPolicy} that will be used
* to create a {@link Classifier} to locate a policy.
*/
public void setPolicyMap(Map, RetryPolicy> policyMap) {
this.exceptionClassifier = new SubclassClassifier<>(policyMap, new NeverRetryPolicy());
}
/**
* Setter for an exception classifier. The classifier is responsible for translating
* exceptions to concrete retry policies. Either this property or the policy map
* should be used, but not both.
* @param exceptionClassifier ExceptionClassifier to use
*/
public void setExceptionClassifier(Classifier exceptionClassifier) {
this.exceptionClassifier = exceptionClassifier;
}
/**
* Delegate to the policy currently activated in the context.
*
* @see org.springframework.retry.RetryPolicy#canRetry(org.springframework.retry.RetryContext)
*/
public boolean canRetry(RetryContext context) {
RetryPolicy policy = (RetryPolicy) context;
return policy.canRetry(context);
}
/**
* Delegate to the policy currently activated in the context.
*
* @see org.springframework.retry.RetryPolicy#close(org.springframework.retry.RetryContext)
*/
public void close(RetryContext context) {
RetryPolicy policy = (RetryPolicy) context;
policy.close(context);
}
/**
* Create an active context that proxies a retry policy by choosing a target from the
* policy map.
*
* @see org.springframework.retry.RetryPolicy#open(RetryContext)
*/
public RetryContext open(RetryContext parent) {
return new ExceptionClassifierRetryContext(parent, exceptionClassifier).open(parent);
}
/**
* Delegate to the policy currently activated in the context.
*
* @see org.springframework.retry.RetryPolicy#registerThrowable(org.springframework.retry.RetryContext,
* Throwable)
*/
public void registerThrowable(RetryContext context, Throwable throwable) {
RetryPolicy policy = (RetryPolicy) context;
policy.registerThrowable(context, throwable);
((RetryContextSupport) context).registerThrowable(throwable);
}
private static class ExceptionClassifierRetryContext extends RetryContextSupport implements RetryPolicy {
final private Classifier exceptionClassifier;
// Dynamic: depends on the latest exception:
private RetryPolicy policy;
// Dynamic: depends on the policy:
private RetryContext context;
final private Map contexts = new HashMap<>();
public ExceptionClassifierRetryContext(RetryContext parent,
Classifier exceptionClassifier) {
super(parent);
this.exceptionClassifier = exceptionClassifier;
}
public boolean canRetry(RetryContext context) {
return this.context == null || policy.canRetry(this.context);
}
public void close(RetryContext context) {
// Only close those policies that have been used (opened):
for (RetryPolicy policy : contexts.keySet()) {
policy.close(getContext(policy, context.getParent()));
}
}
public RetryContext open(RetryContext parent) {
return this;
}
public void registerThrowable(RetryContext context, Throwable throwable) {
policy = exceptionClassifier.classify(throwable);
Assert.notNull(policy, "Could not locate policy for exception=[" + throwable + "].");
this.context = getContext(policy, context.getParent());
policy.registerThrowable(this.context, throwable);
}
private RetryContext getContext(RetryPolicy policy, RetryContext parent) {
RetryContext context = contexts.get(policy);
if (context == null) {
context = policy.open(parent);
contexts.put(policy, context);
}
return context;
}
}
}