1 /* 2 * Copyright 2022 Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google LLC nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package com.google.api.gax.rpc; 31 32 import com.google.auto.value.AutoValue; 33 import com.google.common.annotations.VisibleForTesting; 34 import com.google.protobuf.Any; 35 import com.google.protobuf.InvalidProtocolBufferException; 36 import com.google.protobuf.Message; 37 import com.google.rpc.BadRequest; 38 import com.google.rpc.DebugInfo; 39 import com.google.rpc.ErrorInfo; 40 import com.google.rpc.Help; 41 import com.google.rpc.LocalizedMessage; 42 import com.google.rpc.PreconditionFailure; 43 import com.google.rpc.QuotaFailure; 44 import com.google.rpc.RequestInfo; 45 import com.google.rpc.ResourceInfo; 46 import com.google.rpc.RetryInfo; 47 import java.util.List; 48 import javax.annotation.Nullable; 49 50 /** This class contains a list of standard error messages that returns from server. */ 51 @AutoValue 52 public abstract class ErrorDetails { 53 54 /** 55 * This is the most important and special error message. It describes the cause of the error with 56 * structured details that both humans and applications can depend on. 57 */ 58 @Nullable getErrorInfo()59 public ErrorInfo getErrorInfo() { 60 return unpack(ErrorInfo.class); 61 } 62 63 /** 64 * Describes when the clients can retry a failed request. Clients could ignore the recommendation 65 * here or retry when this information is missing from error responses. 66 */ 67 @Nullable getRetryInfo()68 public RetryInfo getRetryInfo() { 69 return unpack(RetryInfo.class); 70 } 71 72 /** Describes additional debugging info. */ 73 @Nullable getDebugInfo()74 public DebugInfo getDebugInfo() { 75 return unpack(DebugInfo.class); 76 } 77 78 /** Describes how a quota check failed. */ 79 @Nullable getQuotaFailure()80 public QuotaFailure getQuotaFailure() { 81 return unpack(QuotaFailure.class); 82 } 83 84 /** Describes what preconditions have failed. */ 85 @Nullable getPreconditionFailure()86 public PreconditionFailure getPreconditionFailure() { 87 return unpack(PreconditionFailure.class); 88 } 89 90 /** 91 * Describes violations in a client request. This error type focuses on the syntactic aspects of 92 * the request. 93 */ 94 @Nullable getBadRequest()95 public BadRequest getBadRequest() { 96 return unpack(BadRequest.class); 97 } 98 99 /** 100 * Contains metadata about the request that clients can attach when filing a bug or providing 101 * other forms of feedback. 102 */ 103 @Nullable getRequestInfo()104 public RequestInfo getRequestInfo() { 105 return unpack(RequestInfo.class); 106 } 107 108 /** Describes the resource that is being accessed. */ 109 @Nullable getResourceInfo()110 public ResourceInfo getResourceInfo() { 111 return unpack(ResourceInfo.class); 112 } 113 114 /** Provides links to documentation or for performing an out-of-band action. */ 115 @Nullable getHelp()116 public Help getHelp() { 117 return unpack(Help.class); 118 } 119 120 /** 121 * Provides a localized error message that is safe to return to the user which can be attached to 122 * an RPC error 123 */ 124 @Nullable getLocalizedMessage()125 public LocalizedMessage getLocalizedMessage() { 126 return unpack(LocalizedMessage.class); 127 } 128 129 /** This is a list of raw/unparsed error messages that returns from server. */ 130 @Nullable getRawErrorMessages()131 abstract List<Any> getRawErrorMessages(); 132 builder()133 public static Builder builder() { 134 return new AutoValue_ErrorDetails.Builder(); 135 } 136 137 @AutoValue.Builder 138 public abstract static class Builder { 139 setRawErrorMessages(List<Any> rawErrorMessages)140 public abstract Builder setRawErrorMessages(List<Any> rawErrorMessages); 141 build()142 public abstract ErrorDetails build(); 143 } 144 145 @VisibleForTesting unpack(Class<T> errorTypeClazz)146 <T extends Message> T unpack(Class<T> errorTypeClazz) { 147 List<Any> rawErrorMessages = getRawErrorMessages(); 148 if (rawErrorMessages == null) { 149 return null; 150 } 151 for (Any detail : rawErrorMessages) { 152 if (!detail.is(errorTypeClazz)) { 153 continue; 154 } 155 try { 156 return detail.unpack(errorTypeClazz); 157 } catch (InvalidProtocolBufferException e) { 158 throw new ProtocolBufferParsingException( 159 String.format( 160 "Failed to unpack %s from raw error messages", errorTypeClazz.getSimpleName()), 161 e); 162 } 163 } 164 return null; 165 } 166 } 167