All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.retry.RetryResult Maven / Gradle / Ivy

Go to download

Kiwi is a utility library. We really like Google's Guava, and also use Apache Commons. But if they don't have something we need, and we think it is useful, this is where we put it.

There is a newer version: 4.5.2
Show newest version
package org.kiwiproject.retry;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.nonNull;
import static java.util.stream.Collectors.toSet;
import static org.kiwiproject.collect.KiwiLists.isNullOrEmpty;
import static org.kiwiproject.collect.KiwiLists.last;

import lombok.Getter;
import org.kiwiproject.base.UUIDs;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 * Defines a result of one or more attempts to get some type of object. The list of errors should reflect the order
 * in which errors occurred, e.g. the first error should be the error for the first attempt, second error should be
 * the error for the second attempt, etc.
 * 

* A unique identifier is automatically assigned to new {@link RetryResult} instances for easy identification, e.g. * when logging retry exceptions. *

* Note that there is nothing precluding a {@link RetryResult} from representing a failure but not actually have any * errors. This could happen, for example, if retry code executes a {@link java.util.function.Supplier} * and that supplier is implemented to catch all exceptions and return {@code null} to force a retry. We generally * recommend to implement Suppliers to throw exceptions when errors occur. They will need to be subclasses of * {@link RuntimeException} since {@link java.util.function.Supplier} doesn't permit checked exceptions, plus we * generally prefer unchecked exceptions. * * @param the result type */ @Getter public class RetryResult { private final String resultUuid; private final int numAttemptsMade; private final int maxAttempts; private final T object; private final List errors; /** * Create new instance. * * @param numAttemptsMade the number of attempts (must be less than or equal to max attempts) * @param maxAttempts the maximum number of attempts * @param object the result, or {@code null} * @param errors a list containing any errors that occurred on attempts, or {@code null} or empty list * if no errors occurred */ public RetryResult(int numAttemptsMade, int maxAttempts, @Nullable T object, @Nullable List errors) { checkArgument(numAttemptsMade <= maxAttempts, "numAttemptsMade (%s) is not less or equal to maxAttempts (%s)", numAttemptsMade, maxAttempts); this.resultUuid = UUIDs.randomUUIDString(); this.numAttemptsMade = numAttemptsMade; this.maxAttempts = maxAttempts; this.object = object; this.errors = isNullOrEmpty(errors) ? List.of() : List.copyOf(errors); } /** * The result succeeded if this result has an object. * * @return true if the result object is not null, otherwise false */ public boolean succeeded() { return hasObject(); } /** * The result failed if this result does not have an object. * * @return true if the result object is null, otherwise false */ public boolean failed() { return !succeeded(); } /** * Does this result have an object that was successfully retrieved before the maximum number of attempts? * * @return true if the result object is not null, otherwise false */ public boolean hasObject() { return nonNull(object); } /** * Assumes there is an object an returns it, otherwise throws an exception. *

* You should check if an object exists before calling this. Or, consider using {@link #getObjectIfPresent()}. * * @return the result object * @throws IllegalStateException if this result does not have an object */ public T getObject() { return getObjectIfPresent() .orElseThrow(() -> new IllegalStateException("No object is present in this result")); } /** * Returns an {@link Optional} that contains the object if this result was successful, otherwise it will be empty. * * @return an Optional that may contain a result, or be empty */ public Optional getObjectIfPresent() { return Optional.ofNullable(object); } /** * Whether more than one attempt was made to retrieve the object. * * @return true if the number of attempts is more than one */ public boolean hasMoreThanOneAttempt() { return getNumAttemptsMade() > 1; } /** * Did any attempts fail with an exception? The overall result can still be successful if an object is obtained * before the maximum number of attempts is reached. * * @return true if there are any errors that occurred (independent of overall success/failure) */ public boolean hasAnyErrors() { return !errors.isEmpty(); } /** * The number of failed attempts, which can be zero up to the maximum number of attempts. A number greater than * zero does not represent overall failure, however, since a result could have been obtained even if * there were errors. * * @return the number of errors */ public int getNumErrors() { return errors.size(); } /** * Assumes there is at least one error, and returns the last one that was thrown regardless of the number * of attempts. *

* You should check if there are any errors, e.g. using {@link #hasAnyErrors()}, before calling this method. * Alternatively consider using {@link #getLastErrorIfPresent}. * * @return the most recent exception that occurred * @throws IllegalStateException if this result does not have any errors */ public Exception getLastError() { return getLastErrorIfPresent() .orElseThrow(() -> new IllegalStateException("No errors exist in this result")); } /** * Returns an {@link Optional} that contains the last error if this result has any errors, otherwise empty. * * @return an Optional that may contain an error, or be empty */ public Optional getLastErrorIfPresent() { return errors.isEmpty() ? Optional.empty() : Optional.of(last(errors)); } /** * Return a set containing the unique error types in this result. There is NO guarantee whatsoever about the * order of the unique error types, so don't make any assumptions. That's why the return type is {@link Set}. * * @return set of unique error types (class names) */ public Set getUniqueErrorTypes() { return errors.stream() .map(e -> e.getClass().getName()) .collect(toSet()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy