|
| 1 | +package org.jenkinsci.plugins.workflow.steps; |
| 2 | + |
| 3 | +import edu.umd.cs.findbugs.annotations.CheckForNull; |
| 4 | +import edu.umd.cs.findbugs.annotations.NonNull; |
| 5 | +import org.kohsuke.accmod.Restricted; |
| 6 | +import org.kohsuke.accmod.restrictions.Beta; |
| 7 | + |
| 8 | +import java.io.Serializable; |
| 9 | + |
| 10 | +/** |
| 11 | + * Interface destined for {@link StepContext#get} to rewrite or wrap {@link Throwable}s. |
| 12 | + * Pass into {@link BodyInvoker#withContext}. |
| 13 | + */ |
| 14 | +@FunctionalInterface |
| 15 | +@Restricted(Beta.class) |
| 16 | +public interface FailureHandler extends Serializable { |
| 17 | + |
| 18 | + /** |
| 19 | + * Intercept the supplied {@code Throwable}. |
| 20 | + * @param ctx the context of the step being executed |
| 21 | + * @param t the original {@code Throwable} |
| 22 | + * @return the new {@code Throwable} to propagate |
| 23 | + */ |
| 24 | + @NonNull |
| 25 | + Throwable handle(@NonNull StepContext ctx, @NonNull Throwable t); |
| 26 | + |
| 27 | + /** |
| 28 | + * Looks up in the current context for a {@link FailureHandler} and runs it against the given {@code Throwable}. |
| 29 | + * @param ctx the context of the step being executed |
| 30 | + * @param t the original {@code Throwable} |
| 31 | + * @return the new {@code Throwable} to propagate |
| 32 | + */ |
| 33 | + static @NonNull Throwable apply(@NonNull StepContext ctx, |
| 34 | + @NonNull Throwable t) { |
| 35 | + try { |
| 36 | + FailureHandler h = ctx.get(FailureHandler.class); |
| 37 | + if (h == null) { |
| 38 | + return t; |
| 39 | + } |
| 40 | + return h.handle(ctx, t); |
| 41 | + } catch (Throwable x) { |
| 42 | + t.addSuppressed(x); |
| 43 | + return t; |
| 44 | + } |
| 45 | + } |
| 46 | + |
| 47 | + /** |
| 48 | + * Merge together two {@link FailureHandler}. |
| 49 | + * @param original an original one, such as one already found in a context |
| 50 | + * @param subsequent what you are adding |
| 51 | + * @return a {@link FailureHandler} which runs them both in that sequence (or, as a convenience, just {@code subsequent} in case {@code original} is null) |
| 52 | + */ |
| 53 | + static FailureHandler merge(@CheckForNull FailureHandler original, @NonNull FailureHandler subsequent) { |
| 54 | + if (original == null) { |
| 55 | + return subsequent; |
| 56 | + } |
| 57 | + return (ctx, t) -> subsequent.handle(ctx, original.handle(ctx, t)); |
| 58 | + } |
| 59 | +} |
0 commit comments