• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.cloud.http;
18 
19 import com.google.api.client.googleapis.json.GoogleJsonError;
20 import com.google.api.client.googleapis.json.GoogleJsonResponseException;
21 import com.google.api.client.http.HttpResponseException;
22 import com.google.api.core.InternalApi;
23 import com.google.cloud.BaseServiceException;
24 import com.google.common.base.MoreObjects;
25 import java.io.IOException;
26 import java.util.Set;
27 
28 /** Base class for all exceptions from http-based services. */
29 public class BaseHttpServiceException extends BaseServiceException {
30 
31   private static final long serialVersionUID = -5793034110344127954L;
32   public static final int UNKNOWN_CODE = 0;
33 
34   @InternalApi("This class should only be extended within google-cloud-java")
BaseHttpServiceException( IOException exception, boolean idempotent, Set<BaseServiceException.Error> retryableErrors)35   protected BaseHttpServiceException(
36       IOException exception, boolean idempotent, Set<BaseServiceException.Error> retryableErrors) {
37     super(makeExceptionData(exception, idempotent, retryableErrors));
38   }
39 
makeExceptionData( IOException exception, boolean idempotent, Set<BaseServiceException.Error> retryableErrors)40   private static ExceptionData makeExceptionData(
41       IOException exception, boolean idempotent, Set<BaseServiceException.Error> retryableErrors) {
42     int code = UNKNOWN_CODE;
43     String reason = null;
44     String location = null;
45     String debugInfo = null;
46     Boolean retryable = null;
47     if (exception instanceof HttpResponseException) {
48       if (exception instanceof GoogleJsonResponseException) {
49         GoogleJsonError jsonError = ((GoogleJsonResponseException) exception).getDetails();
50         if (jsonError != null) {
51           BaseServiceException.Error error =
52               new BaseServiceException.Error(jsonError.getCode(), reason(jsonError));
53           code = error.getCode();
54           reason = error.getReason();
55           retryable = error.isRetryable(idempotent, retryableErrors);
56           if (reason != null) {
57             GoogleJsonError.ErrorInfo errorInfo = jsonError.getErrors().get(0);
58             location = errorInfo.getLocation();
59             debugInfo = (String) errorInfo.get("debugInfo");
60           }
61         } else {
62           code = ((GoogleJsonResponseException) exception).getStatusCode();
63           retryable = BaseServiceException.isRetryable(code, null, idempotent, retryableErrors);
64         }
65       } else {
66         // In cases where an exception is an instance of HttpResponseException but not
67         // an instance of GoogleJsonResponseException, check the status code to determine whether
68         // it's retryable
69         code = ((HttpResponseException) exception).getStatusCode();
70         retryable = BaseServiceException.isRetryable(code, null, idempotent, retryableErrors);
71       }
72     }
73     return ExceptionData.newBuilder()
74         .setMessage(message(exception))
75         .setCause(exception)
76         .setRetryable(
77             MoreObjects.firstNonNull(
78                 retryable, BaseServiceException.isRetryable(idempotent, exception)))
79         .setCode(code)
80         .setReason(reason)
81         .setLocation(location)
82         .setDebugInfo(debugInfo)
83         .build();
84   }
85 
86   @InternalApi("This class should only be extended within google-cloud-java")
BaseHttpServiceException( GoogleJsonError googleJsonError, boolean idempotent, Set<BaseServiceException.Error> retryableErrors)87   protected BaseHttpServiceException(
88       GoogleJsonError googleJsonError,
89       boolean idempotent,
90       Set<BaseServiceException.Error> retryableErrors) {
91     super(makeExceptionData(googleJsonError, idempotent, retryableErrors));
92   }
93 
makeExceptionData( GoogleJsonError googleJsonError, boolean idempotent, Set<BaseServiceException.Error> retryableErrors)94   private static ExceptionData makeExceptionData(
95       GoogleJsonError googleJsonError,
96       boolean idempotent,
97       Set<BaseServiceException.Error> retryableErrors) {
98     int code = googleJsonError.getCode();
99     String reason = reason(googleJsonError);
100 
101     ExceptionData.Builder exceptionData = ExceptionData.newBuilder();
102     exceptionData
103         .setMessage(googleJsonError.getMessage())
104         .setCause(null)
105         .setRetryable(BaseServiceException.isRetryable(code, reason, idempotent, retryableErrors))
106         .setCode(code)
107         .setReason(reason);
108     if (reason != null) {
109       GoogleJsonError.ErrorInfo errorInfo = googleJsonError.getErrors().get(0);
110       exceptionData.setLocation(errorInfo.getLocation());
111       exceptionData.setDebugInfo((String) errorInfo.get("debugInfo"));
112     } else {
113       exceptionData.setLocation(null);
114       exceptionData.setDebugInfo(null);
115     }
116     return exceptionData.build();
117   }
118 
119   @InternalApi("This class should only be extended within google-cloud-java")
BaseHttpServiceException( int code, String message, String reason, boolean idempotent, Set<BaseServiceException.Error> retryableErrors)120   protected BaseHttpServiceException(
121       int code,
122       String message,
123       String reason,
124       boolean idempotent,
125       Set<BaseServiceException.Error> retryableErrors) {
126     this(code, message, reason, idempotent, retryableErrors, null);
127   }
128 
129   @InternalApi("This class should only be extended within google-cloud-java")
BaseHttpServiceException( int code, String message, String reason, boolean idempotent, Set<BaseServiceException.Error> retryableErrors, Throwable cause)130   protected BaseHttpServiceException(
131       int code,
132       String message,
133       String reason,
134       boolean idempotent,
135       Set<BaseServiceException.Error> retryableErrors,
136       Throwable cause) {
137     super(
138         ExceptionData.newBuilder()
139             .setMessage(message)
140             .setCause(cause)
141             .setRetryable(
142                 BaseServiceException.isRetryable(code, reason, idempotent, retryableErrors))
143             .setCode(code)
144             .setReason(reason)
145             .setLocation(null)
146             .setDebugInfo(null)
147             .build());
148   }
149 
reason(GoogleJsonError error)150   private static String reason(GoogleJsonError error) {
151     if (error.getErrors() != null && !error.getErrors().isEmpty()) {
152       return error.getErrors().get(0).getReason();
153     }
154     return null;
155   }
156 
message(IOException exception)157   private static String message(IOException exception) {
158     if (exception instanceof GoogleJsonResponseException) {
159       GoogleJsonError details = ((GoogleJsonResponseException) exception).getDetails();
160       if (details != null) {
161         return details.getMessage();
162       }
163     }
164     return exception.getMessage();
165   }
166 }
167