Skip to content

Commit

Permalink
Refactor BaseServiceException
Browse files Browse the repository at this point in the history
  • Loading branch information
mziccard committed Jan 18, 2016
1 parent 767c41f commit f350a54
Show file tree
Hide file tree
Showing 24 changed files with 871 additions and 436 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ static Entity fromPb(Access access) {
}
// Unreachable
throw new BigQueryException(BigQueryException.UNKNOWN_CODE,
"Unrecognized access configuration", false);
"Unrecognized access configuration");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@

package com.google.gcloud.bigquery;

import com.google.common.collect.ImmutableSet;
import com.google.gcloud.BaseServiceException;
import com.google.gcloud.RetryHelper.RetryHelperException;
import com.google.gcloud.RetryHelper.RetryInterruptedException;

import java.io.IOException;
import java.util.Set;

/**
* BigQuery service exception.
*
Expand All @@ -28,20 +32,30 @@
*/
public class BigQueryException extends BaseServiceException {

private static final long serialVersionUID = -5504832700512784654L;
public static final int UNKNOWN_CODE = -1;
// see: https://cloud.google.com/bigquery/troubleshooting-errors
private static final Set<Error> RETRYABLE_ERRORS = ImmutableSet.of(
new Error(500, null),
new Error(502, null),
new Error(503, null),
new Error(504, null));
private static final long serialVersionUID = -5006625989225438209L;

private final BigQueryError error;

public BigQueryException(int code, String message, boolean retryable) {
this(code, message, retryable, null);
public BigQueryException(int code, String message) {
this(code, message, null);
}

public BigQueryException(int code, String message, boolean retryable, BigQueryError error) {
super(code, message, retryable);
public BigQueryException(int code, String message, BigQueryError error) {
super(code, message, error != null ? error.reason() : null, true);
this.error = error;
}

public BigQueryException(IOException exception) {
super(exception, true);
this.error = null;
}

/**
* Returns the {@link BigQueryError} that caused this exception. Returns {@code null} if none
* exists.
Expand All @@ -50,20 +64,20 @@ public BigQueryError error() {
return error;
}

@Override
protected Set<Error> retryableErrors() {
return RETRYABLE_ERRORS;
}

/**
* Translate RetryHelperException to the BigQueryException that caused the error. This method will
* always throw an exception.
*
* @throws BigQueryException when {@code ex} was caused by a {@code BigQueryException}
* @throws RetryInterruptedException when {@code ex} is a {@code RetryInterruptedException}
*/
static BigQueryException translateAndThrow(RetryHelperException ex) {
if (ex.getCause() instanceof BigQueryException) {
throw (BigQueryException) ex.getCause();
}
if (ex instanceof RetryInterruptedException) {
RetryInterruptedException.propagate();
}
throw new BigQueryException(UNKNOWN_CODE, ex.getMessage(), false);
public static BigQueryException translateAndThrow(RetryHelperException ex) {
BaseServiceException.translateAndThrow(ex);
throw new BigQueryException(UNKNOWN_CODE, ex.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import static com.google.gcloud.spi.BigQueryRpc.Option.TIMEOUT;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;

import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
Expand All @@ -46,24 +44,19 @@
import com.google.api.services.bigquery.model.TableRow;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

import com.google.gcloud.bigquery.BigQueryError;
import com.google.gcloud.bigquery.BigQueryException;
import com.google.gcloud.bigquery.BigQueryOptions;

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class DefaultBigQueryRpc implements BigQueryRpc {

public static final String DEFAULT_PROJECTION = "full";
// see: https://cloud.google.com/bigquery/troubleshooting-errors
private static final Set<Integer> RETRYABLE_CODES = ImmutableSet.of(500, 502, 503, 504);
private final BigQueryOptions options;
private final Bigquery bigquery;

Expand All @@ -78,28 +71,7 @@ public DefaultBigQueryRpc(BigQueryOptions options) {
}

private static BigQueryException translate(IOException exception) {
BigQueryException translated;
if (exception instanceof GoogleJsonResponseException
&& ((GoogleJsonResponseException) exception).getDetails() != null) {
translated = translate(((GoogleJsonResponseException) exception).getDetails());
} else {
translated =
new BigQueryException(BigQueryException.UNKNOWN_CODE, exception.getMessage(), false);
}
translated.initCause(exception);
return translated;
}

private static BigQueryException translate(GoogleJsonError exception) {
boolean retryable = RETRYABLE_CODES.contains(exception.getCode());
BigQueryError bigqueryError = null;
if (exception.getErrors() != null && !exception.getErrors().isEmpty()) {
GoogleJsonError.ErrorInfo error = exception.getErrors().get(0);
bigqueryError = new BigQueryError(error.getReason(), error.getLocation(), error.getMessage(),
(String) error.get("debugInfo"));
}
return new BigQueryException(exception.getCode(), exception.getMessage(), retryable,
bigqueryError);
return new BigQueryException(exception);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.gcloud.bigquery;

import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import com.google.gcloud.BaseServiceException;
import com.google.gcloud.RetryHelper.RetryHelperException;

import org.junit.Test;

import java.io.IOException;
import java.net.SocketTimeoutException;

public class BigQueryExceptionTest {

@Test
public void testBigqueryException() {
BigQueryException exception = new BigQueryException(500, "message");
assertEquals(500, exception.code());
assertEquals("message", exception.getMessage());
assertNull(exception.reason());
assertNull(exception.error());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());

exception = new BigQueryException(502, "message");
assertEquals(502, exception.code());
assertEquals("message", exception.getMessage());
assertNull(exception.reason());
assertNull(exception.error());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());

exception = new BigQueryException(503, "message");
assertEquals(503, exception.code());
assertEquals("message", exception.getMessage());
assertNull(exception.reason());
assertNull(exception.error());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());

exception = new BigQueryException(504, "message");
assertEquals(504, exception.code());
assertEquals("message", exception.getMessage());
assertNull(exception.reason());
assertNull(exception.error());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());

exception = new BigQueryException(400, "message");
assertEquals(400, exception.code());
assertEquals("message", exception.getMessage());
assertNull(exception.reason());
assertNull(exception.error());
assertFalse(exception.retryable());
assertTrue(exception.idempotent());

BigQueryError error = new BigQueryError("reason", null, null);
exception = new BigQueryException(504, "message", error);
assertEquals(504, exception.code());
assertEquals("message", exception.getMessage());
assertEquals("reason", exception.reason());
assertEquals(error, exception.error());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());

IOException cause = new SocketTimeoutException();
exception = new BigQueryException(cause);
assertNull(exception.reason());
assertNull(exception.getMessage());
assertTrue(exception.retryable());
assertTrue(exception.idempotent());
assertEquals(cause, exception.getCause());
}

@Test
public void testTranslateAndThrow() throws Exception {
BigQueryException cause = new BigQueryException(503, "message");
RetryHelperException exceptionMock = createMock(RetryHelperException.class);
expect(exceptionMock.getCause()).andReturn(cause).times(2);
replay(exceptionMock);
try {
BigQueryException.translateAndThrow(exceptionMock);
} catch (BaseServiceException ex) {
assertEquals(503, ex.code());
assertEquals("message", ex.getMessage());
assertTrue(ex.retryable());
assertTrue(ex.idempotent());
} finally {
verify(exceptionMock);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ public void testGetQueryResultsWithOptions() {
@Test
public void testRetryableException() {
EasyMock.expect(bigqueryRpcMock.getDataset(DATASET, EMPTY_RPC_OPTIONS))
.andThrow(new BigQueryException(500, "InternalError", true))
.andThrow(new BigQueryException(500, "InternalError"))
.andReturn(DATASET_INFO_WITH_PROJECT.toPb());
EasyMock.replay(bigqueryRpcMock);
bigquery = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service();
Expand All @@ -1021,7 +1021,7 @@ public void testRetryableException() {
public void testNonRetryableException() {
String exceptionMessage = "Not Implemented";
EasyMock.expect(bigqueryRpcMock.getDataset(DATASET, EMPTY_RPC_OPTIONS))
.andThrow(new BigQueryException(501, exceptionMessage, false));
.andThrow(new BigQueryException(501, exceptionMessage));
EasyMock.replay(bigqueryRpcMock);
bigquery = options.toBuilder().retryParams(RetryParams.defaultInstance()).build().service();
thrown.expect(BigQueryException.class);
Expand Down
Loading

0 comments on commit f350a54

Please sign in to comment.