Skip to content

Commit add5924

Browse files
committed
Merge pull request #554 from mziccard/refactor-exception
Refactor service exceptions
2 parents 397b2c1 + 3c81f16 commit add5924

File tree

28 files changed

+890
-532
lines changed

28 files changed

+890
-532
lines changed

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/Acl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static Entity fromPb(Access access) {
104104
}
105105
// Unreachable
106106
throw new BigQueryException(BigQueryException.UNKNOWN_CODE,
107-
"Unrecognized access configuration", false);
107+
"Unrecognized access configuration");
108108
}
109109
}
110110

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/BigQueryException.java

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616

1717
package com.google.gcloud.bigquery;
1818

19+
import com.google.common.collect.ImmutableSet;
1920
import com.google.gcloud.BaseServiceException;
2021
import com.google.gcloud.RetryHelper.RetryHelperException;
2122
import com.google.gcloud.RetryHelper.RetryInterruptedException;
2223

24+
import java.io.IOException;
25+
import java.util.Set;
26+
2327
/**
2428
* BigQuery service exception.
2529
*
@@ -28,20 +32,30 @@
2832
*/
2933
public class BigQueryException extends BaseServiceException {
3034

31-
private static final long serialVersionUID = -5504832700512784654L;
32-
public static final int UNKNOWN_CODE = -1;
35+
// see: https://cloud.google.com/bigquery/troubleshooting-errors
36+
private static final Set<Error> RETRYABLE_ERRORS = ImmutableSet.of(
37+
new Error(500, null),
38+
new Error(502, null),
39+
new Error(503, null),
40+
new Error(504, null));
41+
private static final long serialVersionUID = -5006625989225438209L;
3342

3443
private final BigQueryError error;
3544

36-
public BigQueryException(int code, String message, boolean retryable) {
37-
this(code, message, retryable, null);
45+
public BigQueryException(int code, String message) {
46+
this(code, message, null);
3847
}
3948

40-
public BigQueryException(int code, String message, boolean retryable, BigQueryError error) {
41-
super(code, message, retryable);
49+
public BigQueryException(int code, String message, BigQueryError error) {
50+
super(code, message, error != null ? error.reason() : null, true);
4251
this.error = error;
4352
}
4453

54+
public BigQueryException(IOException exception) {
55+
super(exception, true);
56+
this.error = null;
57+
}
58+
4559
/**
4660
* Returns the {@link BigQueryError} that caused this exception. Returns {@code null} if none
4761
* exists.
@@ -50,20 +64,20 @@ public BigQueryError error() {
5064
return error;
5165
}
5266

67+
@Override
68+
protected Set<Error> retryableErrors() {
69+
return RETRYABLE_ERRORS;
70+
}
71+
5372
/**
5473
* Translate RetryHelperException to the BigQueryException that caused the error. This method will
5574
* always throw an exception.
5675
*
5776
* @throws BigQueryException when {@code ex} was caused by a {@code BigQueryException}
5877
* @throws RetryInterruptedException when {@code ex} is a {@code RetryInterruptedException}
5978
*/
60-
static BigQueryException translateAndThrow(RetryHelperException ex) {
61-
if (ex.getCause() instanceof BigQueryException) {
62-
throw (BigQueryException) ex.getCause();
63-
}
64-
if (ex instanceof RetryInterruptedException) {
65-
RetryInterruptedException.propagate();
66-
}
67-
throw new BigQueryException(UNKNOWN_CODE, ex.getMessage(), false);
79+
static BaseServiceException translateAndThrow(RetryHelperException ex) {
80+
BaseServiceException.translateAndPropagateIfPossible(ex);
81+
throw new BigQueryException(UNKNOWN_CODE, ex.getMessage());
6882
}
6983
}

gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/BigQueryImpl.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
import com.google.common.collect.Lists;
3535
import com.google.common.collect.Maps;
3636
import com.google.gcloud.BaseService;
37-
import com.google.gcloud.ExceptionHandler;
38-
import com.google.gcloud.ExceptionHandler.Interceptor;
3937
import com.google.gcloud.Page;
4038
import com.google.gcloud.PageImpl;
4139
import com.google.gcloud.PageImpl.NextPageFetcher;
@@ -49,27 +47,6 @@
4947

5048
final class BigQueryImpl extends BaseService<BigQueryOptions> implements BigQuery {
5149

52-
private static final Interceptor EXCEPTION_HANDLER_INTERCEPTOR = new Interceptor() {
53-
54-
private static final long serialVersionUID = -7478333733015750774L;
55-
56-
@Override
57-
public RetryResult afterEval(Exception exception, RetryResult retryResult) {
58-
return Interceptor.RetryResult.CONTINUE_EVALUATION;
59-
}
60-
61-
@Override
62-
public RetryResult beforeEval(Exception exception) {
63-
if (exception instanceof BigQueryException) {
64-
boolean retriable = ((BigQueryException) exception).retryable();
65-
return retriable ? Interceptor.RetryResult.RETRY : Interceptor.RetryResult.NO_RETRY;
66-
}
67-
return Interceptor.RetryResult.CONTINUE_EVALUATION;
68-
}
69-
};
70-
static final ExceptionHandler EXCEPTION_HANDLER = ExceptionHandler.builder()
71-
.abortOn(RuntimeException.class).interceptor(EXCEPTION_HANDLER_INTERCEPTOR).build();
72-
7350
private static class DatasetPageFetcher implements NextPageFetcher<DatasetInfo> {
7451

7552
private static final long serialVersionUID = -3057564042439021278L;

gcloud-java-bigquery/src/main/java/com/google/gcloud/spi/DefaultBigQueryRpc.java

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import static java.net.HttpURLConnection.HTTP_OK;
2626

2727
import com.google.api.client.googleapis.json.GoogleJsonError;
28-
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
2928
import com.google.api.client.http.ByteArrayContent;
3029
import com.google.api.client.http.GenericUrl;
3130
import com.google.api.client.http.HttpRequest;
@@ -58,24 +57,19 @@
5857
import com.google.api.services.bigquery.model.TableRow;
5958
import com.google.common.base.Function;
6059
import com.google.common.collect.ImmutableList;
61-
import com.google.common.collect.ImmutableSet;
6260
import com.google.common.collect.Iterables;
6361

64-
import com.google.gcloud.bigquery.BigQueryError;
6562
import com.google.gcloud.bigquery.BigQueryException;
6663
import com.google.gcloud.bigquery.BigQueryOptions;
6764

6865
import java.io.IOException;
6966
import java.math.BigInteger;
7067
import java.util.List;
7168
import java.util.Map;
72-
import java.util.Set;
7369

7470
public class DefaultBigQueryRpc implements BigQueryRpc {
7571

7672
public static final String DEFAULT_PROJECTION = "full";
77-
// see: https://cloud.google.com/bigquery/troubleshooting-errors
78-
private static final Set<Integer> RETRYABLE_CODES = ImmutableSet.of(500, 502, 503, 504);
7973
private static final String BASE_RESUMABLE_URI =
8074
"https://www.googleapis.com/upload/bigquery/v2/projects/";
8175
// see: https://cloud.google.com/bigquery/loading-data-post-request#resume-upload
@@ -94,28 +88,7 @@ public DefaultBigQueryRpc(BigQueryOptions options) {
9488
}
9589

9690
private static BigQueryException translate(IOException exception) {
97-
BigQueryException translated;
98-
if (exception instanceof GoogleJsonResponseException
99-
&& ((GoogleJsonResponseException) exception).getDetails() != null) {
100-
translated = translate(((GoogleJsonResponseException) exception).getDetails());
101-
} else {
102-
translated =
103-
new BigQueryException(BigQueryException.UNKNOWN_CODE, exception.getMessage(), false);
104-
}
105-
translated.initCause(exception);
106-
return translated;
107-
}
108-
109-
private static BigQueryException translate(GoogleJsonError exception) {
110-
boolean retryable = RETRYABLE_CODES.contains(exception.getCode());
111-
BigQueryError bigqueryError = null;
112-
if (exception.getErrors() != null && !exception.getErrors().isEmpty()) {
113-
GoogleJsonError.ErrorInfo error = exception.getErrors().get(0);
114-
bigqueryError = new BigQueryError(error.getReason(), error.getLocation(), error.getMessage(),
115-
(String) error.get("debugInfo"));
116-
}
117-
return new BigQueryException(exception.getCode(), exception.getMessage(), retryable,
118-
bigqueryError);
91+
return new BigQueryException(exception);
11992
}
12093

12194
@Override
@@ -489,10 +462,7 @@ public void write(String uploadId, byte[] toWrite, int toWriteOffset, long destO
489462
if (exception != null) {
490463
throw exception;
491464
}
492-
GoogleJsonError error = new GoogleJsonError();
493-
error.setCode(code);
494-
error.setMessage(message);
495-
throw translate(error);
465+
throw new BigQueryException(code, message);
496466
}
497467
} catch (IOException ex) {
498468
throw translate(ex);
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2015 Google Inc. All Rights Reserved.
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.gcloud.bigquery;
18+
19+
import static org.easymock.EasyMock.createMock;
20+
import static org.easymock.EasyMock.expect;
21+
import static org.easymock.EasyMock.replay;
22+
import static org.easymock.EasyMock.verify;
23+
import static org.junit.Assert.assertEquals;
24+
import static org.junit.Assert.assertFalse;
25+
import static org.junit.Assert.assertNull;
26+
import static org.junit.Assert.assertTrue;
27+
28+
import com.google.gcloud.BaseServiceException;
29+
import com.google.gcloud.RetryHelper.RetryHelperException;
30+
31+
import org.junit.Test;
32+
33+
import java.io.IOException;
34+
import java.net.SocketTimeoutException;
35+
36+
public class BigQueryExceptionTest {
37+
38+
@Test
39+
public void testBigqueryException() {
40+
BigQueryException exception = new BigQueryException(500, "message");
41+
assertEquals(500, exception.code());
42+
assertEquals("message", exception.getMessage());
43+
assertNull(exception.reason());
44+
assertNull(exception.error());
45+
assertTrue(exception.retryable());
46+
assertTrue(exception.idempotent());
47+
48+
exception = new BigQueryException(502, "message");
49+
assertEquals(502, exception.code());
50+
assertEquals("message", exception.getMessage());
51+
assertNull(exception.reason());
52+
assertNull(exception.error());
53+
assertTrue(exception.retryable());
54+
assertTrue(exception.idempotent());
55+
56+
exception = new BigQueryException(503, "message");
57+
assertEquals(503, exception.code());
58+
assertEquals("message", exception.getMessage());
59+
assertNull(exception.reason());
60+
assertNull(exception.error());
61+
assertTrue(exception.retryable());
62+
assertTrue(exception.idempotent());
63+
64+
exception = new BigQueryException(504, "message");
65+
assertEquals(504, exception.code());
66+
assertEquals("message", exception.getMessage());
67+
assertNull(exception.reason());
68+
assertNull(exception.error());
69+
assertTrue(exception.retryable());
70+
assertTrue(exception.idempotent());
71+
72+
exception = new BigQueryException(400, "message");
73+
assertEquals(400, exception.code());
74+
assertEquals("message", exception.getMessage());
75+
assertNull(exception.reason());
76+
assertNull(exception.error());
77+
assertFalse(exception.retryable());
78+
assertTrue(exception.idempotent());
79+
80+
BigQueryError error = new BigQueryError("reason", null, null);
81+
exception = new BigQueryException(504, "message", error);
82+
assertEquals(504, exception.code());
83+
assertEquals("message", exception.getMessage());
84+
assertEquals("reason", exception.reason());
85+
assertEquals(error, exception.error());
86+
assertTrue(exception.retryable());
87+
assertTrue(exception.idempotent());
88+
89+
IOException cause = new SocketTimeoutException();
90+
exception = new BigQueryException(cause);
91+
assertNull(exception.reason());
92+
assertNull(exception.getMessage());
93+
assertTrue(exception.retryable());
94+
assertTrue(exception.idempotent());
95+
assertEquals(cause, exception.getCause());
96+
}
97+
98+
@Test
99+
public void testTranslateAndThrow() throws Exception {
100+
BigQueryException cause = new BigQueryException(503, "message");
101+
RetryHelperException exceptionMock = createMock(RetryHelperException.class);
102+
expect(exceptionMock.getCause()).andReturn(cause).times(2);
103+
replay(exceptionMock);
104+
try {
105+
BigQueryException.translateAndThrow(exceptionMock);
106+
} catch (BaseServiceException ex) {
107+
assertEquals(503, ex.code());
108+
assertEquals("message", ex.getMessage());
109+
assertTrue(ex.retryable());
110+
assertTrue(ex.idempotent());
111+
} finally {
112+
verify(exceptionMock);
113+
}
114+
}
115+
}

gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/BigQueryImplTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ public void testWriter() {
10221022
@Test
10231023
public void testRetryableException() {
10241024
EasyMock.expect(bigqueryRpcMock.getDataset(DATASET, EMPTY_RPC_OPTIONS))
1025-
.andThrow(new BigQueryException(500, "InternalError", true))
1025+
.andThrow(new BigQueryException(500, "InternalError"))
10261026
.andReturn(DATASET_INFO_WITH_PROJECT.toPb());
10271027
EasyMock.replay(bigqueryRpcMock);
10281028
bigquery = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service();
@@ -1034,7 +1034,7 @@ public void testRetryableException() {
10341034
public void testNonRetryableException() {
10351035
String exceptionMessage = "Not Implemented";
10361036
EasyMock.expect(bigqueryRpcMock.getDataset(DATASET, EMPTY_RPC_OPTIONS))
1037-
.andThrow(new BigQueryException(501, exceptionMessage, false));
1037+
.andThrow(new BigQueryException(501, exceptionMessage));
10381038
EasyMock.replay(bigqueryRpcMock);
10391039
bigquery = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service();
10401040
thrown.expect(BigQueryException.class);

gcloud-java-core/src/main/java/com/google/gcloud/BaseService.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.gcloud;
1818

19+
import com.google.gcloud.ExceptionHandler.Interceptor;
20+
1921
/**
2022
* Base class for service objects.
2123
*
@@ -24,6 +26,29 @@
2426
public abstract class BaseService<OptionsT extends ServiceOptions<?, ?, OptionsT>>
2527
implements Service<OptionsT> {
2628

29+
public static final Interceptor EXCEPTION_HANDLER_INTERCEPTOR = new Interceptor() {
30+
31+
private static final long serialVersionUID = -8429573486870467828L;
32+
33+
@Override
34+
public RetryResult afterEval(Exception exception, RetryResult retryResult) {
35+
return Interceptor.RetryResult.CONTINUE_EVALUATION;
36+
}
37+
38+
@Override
39+
public RetryResult beforeEval(Exception exception) {
40+
if (exception instanceof BaseServiceException) {
41+
boolean retriable = ((BaseServiceException) exception).retryable();
42+
return retriable ? Interceptor.RetryResult.RETRY : Interceptor.RetryResult.NO_RETRY;
43+
}
44+
return Interceptor.RetryResult.CONTINUE_EVALUATION;
45+
}
46+
};
47+
public static final ExceptionHandler EXCEPTION_HANDLER = ExceptionHandler.builder()
48+
.abortOn(RuntimeException.class)
49+
.interceptor(EXCEPTION_HANDLER_INTERCEPTOR)
50+
.build();
51+
2752
private final OptionsT options;
2853

2954
protected BaseService(OptionsT options) {

0 commit comments

Comments
 (0)