| /* |
| * 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.ratis.retry; |
| |
| import org.apache.ratis.util.JavaUtils; |
| import org.apache.ratis.util.Preconditions; |
| |
| import java.util.Collections; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.function.Supplier; |
| |
| /** |
| * Exception dependent retry policy. |
| * |
| * If exception is defined in policyMap, will use the retry policy |
| * configured to that exception or else will use the default policy. |
| */ |
| public final class ExceptionDependentRetry implements RetryPolicy { |
| |
| public static class Builder { |
| private RetryPolicy defaultPolicy; |
| private final Map<String, RetryPolicy> exceptionNameToPolicyMap = |
| new TreeMap<>(); |
| private int maxAttempts = Integer.MAX_VALUE; |
| |
| public Builder setExceptionToPolicy(Class<? extends Throwable> exception, |
| RetryPolicy retryPolicy) { |
| Preconditions.assertTrue(retryPolicy != null, "Exception to policy should not be null"); |
| final RetryPolicy previous = exceptionNameToPolicyMap.put(exception.getName(), retryPolicy); |
| Preconditions.assertNull(previous, () -> "The exception " + exception + " is already set to " + previous); |
| return this; |
| } |
| |
| public Builder setDefaultPolicy(RetryPolicy retryPolicy) { |
| Preconditions.assertTrue(retryPolicy != null, "Default Policy should not be null"); |
| this.defaultPolicy = retryPolicy; |
| return this; |
| } |
| |
| public Builder setMaxAttempts(int attempts) { |
| this.maxAttempts = attempts; |
| return this; |
| } |
| |
| public ExceptionDependentRetry build() { |
| return new ExceptionDependentRetry(defaultPolicy, exceptionNameToPolicyMap, maxAttempts); |
| } |
| } |
| |
| public static Builder newBuilder() { |
| return new Builder(); |
| } |
| |
| private final RetryPolicy defaultPolicy; |
| private final Map<String, RetryPolicy> exceptionNameToPolicyMap; |
| private final int maxAttempts; |
| private final Supplier<String> toStringSupplier; |
| |
| private ExceptionDependentRetry(RetryPolicy defaultPolicy, |
| Map<String, RetryPolicy> policyMap, int maxAttempts) { |
| Preconditions.assertTrue(defaultPolicy != null, "Default Policy should not be null"); |
| this.defaultPolicy = defaultPolicy; |
| this.exceptionNameToPolicyMap = Collections.unmodifiableMap(policyMap); |
| this.maxAttempts = maxAttempts; |
| this.toStringSupplier = JavaUtils.memoize(() -> { |
| final StringBuilder b = new StringBuilder(JavaUtils.getClassSimpleName(getClass())).append("(") |
| .append("maxAttempts=").append(maxAttempts).append("; ") |
| .append("defaultPolicy=").append(defaultPolicy).append("; ") |
| .append("map={"); |
| policyMap.forEach((key, value) -> b.append(key).append("->").append(value).append(", ")); |
| b.setLength(b.length() - 2); |
| return b.append("})").toString(); |
| }); |
| } |
| |
| @Override |
| public Action handleAttemptFailure(Event event) { |
| RetryPolicy policy = null; |
| |
| // If exception is defined in policy map use that or else go with the |
| // default one. We go with default one in 2 cases. |
| // 1. If policy map does not have exception mapped to policy. |
| // 2. If event has exception value null. |
| if (event.getCause() != null) { |
| policy = exceptionNameToPolicyMap.get(event.getCause().getClass().getName()); |
| } |
| |
| if (policy == null) { |
| policy = defaultPolicy; |
| } |
| |
| return event.getAttemptCount() < maxAttempts ? policy.handleAttemptFailure(event::getCauseCount) : |
| NO_RETRY_ACTION; |
| } |
| |
| @Override |
| public String toString() { |
| return toStringSupplier.get(); |
| } |
| } |