Line data Source code
1 : // Copyright (C) 2021 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.cancellation; 16 : 17 : import com.google.common.base.Throwables; 18 : import com.google.gerrit.common.Nullable; 19 : import java.util.Optional; 20 : import org.apache.commons.text.WordUtils; 21 : 22 : /** Exception to signal that the current request is cancelled and should be aborted. */ 23 : public class RequestCancelledException extends RuntimeException { 24 : private static final long serialVersionUID = 1L; 25 : 26 : /** 27 : * Checks whether the given exception was caused by {@link RequestCancelledException}. If yes, the 28 : * {@link RequestCancelledException} is returned. If not, {@link Optional#empty()} is returned. 29 : */ 30 : public static Optional<RequestCancelledException> getFromCausalChain(Throwable e) { 31 8 : return Throwables.getCausalChain(e).stream() 32 8 : .filter(RequestCancelledException.class::isInstance) 33 8 : .map(RequestCancelledException.class::cast) 34 8 : .findFirst(); 35 : } 36 : 37 : private final RequestStateProvider.Reason cancellationReason; 38 : private final Optional<String> cancellationMessage; 39 : 40 : /** 41 : * Create a {@code RequestCancelledException}. 42 : * 43 : * @param cancellationReason the reason why the request is cancelled 44 : * @param cancellationMessage an optional message providing details about the cancellation 45 : */ 46 : public RequestCancelledException( 47 : RequestStateProvider.Reason cancellationReason, @Nullable String cancellationMessage) { 48 3 : super(createMessage(cancellationReason, cancellationMessage)); 49 3 : this.cancellationReason = cancellationReason; 50 3 : this.cancellationMessage = Optional.ofNullable(cancellationMessage); 51 3 : } 52 : 53 : private static String createMessage( 54 : RequestStateProvider.Reason cancellationReason, @Nullable String message) { 55 3 : StringBuilder messageBuilder = new StringBuilder(); 56 3 : messageBuilder.append(String.format("Request cancelled: %s", cancellationReason.name())); 57 3 : if (message != null) { 58 3 : messageBuilder.append(String.format(" (%s)", message)); 59 : } 60 3 : return messageBuilder.toString(); 61 : } 62 : 63 : /** Returns the reason why the request is cancelled. */ 64 : public RequestStateProvider.Reason getCancellationReason() { 65 3 : return cancellationReason; 66 : } 67 : 68 : /** Returns the cancellation reason as a user-readable string. */ 69 : public String formatCancellationReason() { 70 2 : return WordUtils.capitalizeFully(cancellationReason.name().replaceAll("_", " ")); 71 : } 72 : 73 : /** 74 : * Returns a message providing details about the cancellation, or {@link Optional#empty()} if none 75 : * is available. 76 : */ 77 : public Optional<String> getCancellationMessage() { 78 3 : return cancellationMessage; 79 : } 80 : }