diff --git a/google-ads/src/main/java/com/google/ads/googleads/lib/GrpcGoogleAdsCallableFactory.java b/google-ads/src/main/java/com/google/ads/googleads/lib/GrpcGoogleAdsCallableFactory.java
index ced2c9cbc7..4aa4b6f2c4 100644
--- a/google-ads/src/main/java/com/google/ads/googleads/lib/GrpcGoogleAdsCallableFactory.java
+++ b/google-ads/src/main/java/com/google/ads/googleads/lib/GrpcGoogleAdsCallableFactory.java
@@ -15,9 +15,10 @@
*/
package com.google.ads.googleads.lib;
-import com.google.ads.googleads.lib.ExceptionTransformingCallable;
-import com.google.ads.googleads.lib.ExceptionTransformingCallable.ExceptionTransformation;
-import com.google.ads.googleads.lib.GoogleAdsExceptionTransformation;
+import com.google.ads.googleads.lib.callables.ExceptionTransformation;
+import com.google.ads.googleads.lib.callables.ExceptionTransformingServerStreamingCallable;
+import com.google.ads.googleads.lib.callables.ExceptionTransformingUnaryCallable;
+import com.google.ads.googleads.lib.callables.GoogleAdsExceptionTransformation;
import com.google.api.gax.grpc.GrpcCallSettings;
import com.google.api.gax.grpc.GrpcCallableFactory;
import com.google.api.gax.grpc.GrpcStubCallableFactory;
@@ -37,42 +38,61 @@
import com.google.longrunning.Operation;
import com.google.longrunning.stub.OperationsStub;
+/**
+ * Defines the factory used to create instances for all Google Ads services.
+ *
+ *
Used in place of the default generated code to override the exceptions generated to throw
+ * GoogleAdsException instead of ApiException.
+ */
public class GrpcGoogleAdsCallableFactory implements GrpcStubCallableFactory {
- private static final ExceptionTransformation googleAdsExceptionTransformation = new GoogleAdsExceptionTransformation();
+ private static final ExceptionTransformation googleAdsExceptionTransformation =
+ new GoogleAdsExceptionTransformation();
- public static UnaryCallable createBaseUnaryCallable(GrpcCallSettings grpcCallSettings, UnaryCallSettings, ?> callSettings, ClientContext clientContext) {
- UnaryCallable callable = GrpcCallableFactory.createBaseUnaryCallable(grpcCallSettings, callSettings, clientContext);
- return new ExceptionTransformingCallable<>(callable, googleAdsExceptionTransformation);
+ public static UnaryCallable createBaseUnaryCallable(
+ GrpcCallSettings grpcCallSettings,
+ UnaryCallSettings, ?> callSettings,
+ ClientContext clientContext) {
+ UnaryCallable callable =
+ GrpcCallableFactory.createBaseUnaryCallable(grpcCallSettings, callSettings, clientContext);
+ return new ExceptionTransformingUnaryCallable<>(callable, googleAdsExceptionTransformation);
}
+ @Override
public UnaryCallable createUnaryCallable(
GrpcCallSettings grpcCallSettings,
UnaryCallSettings callSettings,
ClientContext clientContext) {
- UnaryCallable callable = createBaseUnaryCallable(grpcCallSettings, callSettings, clientContext);
+ UnaryCallable callable =
+ createBaseUnaryCallable(grpcCallSettings, callSettings, clientContext);
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
}
+ @Override
public
UnaryCallable createPagedCallable(
GrpcCallSettings grpcCallSettings,
PagedCallSettings pagedCallSettings,
ClientContext clientContext) {
- UnaryCallable innerCallable = createBaseUnaryCallable(grpcCallSettings, pagedCallSettings, clientContext);
- UnaryCallable pagedCallable = Callables.paged(innerCallable, pagedCallSettings);
+ UnaryCallable innerCallable =
+ createBaseUnaryCallable(grpcCallSettings, pagedCallSettings, clientContext);
+ UnaryCallable pagedCallable =
+ Callables.paged(innerCallable, pagedCallSettings);
return pagedCallable.withDefaultCallContext(clientContext.getDefaultCallContext());
}
+ @Override
public UnaryCallable createBatchingCallable(
GrpcCallSettings grpcCallSettings,
BatchingCallSettings batchingCallSettings,
ClientContext clientContext) {
- UnaryCallable callable = createBaseUnaryCallable(grpcCallSettings, batchingCallSettings, clientContext);
+ UnaryCallable callable =
+ createBaseUnaryCallable(grpcCallSettings, batchingCallSettings, clientContext);
callable = Callables.batching(callable, batchingCallSettings, clientContext);
return callable.withDefaultCallContext(clientContext.getDefaultCallContext());
}
+ @Override
public
OperationCallable createOperationCallable(
GrpcCallSettings grpcCallSettings,
@@ -83,6 +103,7 @@ OperationCallable createOperationCallable(
grpcCallSettings, operationCallSettings, clientContext, operationsStub);
}
+ @Override
public
BidiStreamingCallable createBidiStreamingCallable(
GrpcCallSettings grpcCallSettings,
@@ -92,15 +113,20 @@ BidiStreamingCallable createBidiStreamingCallable(
grpcCallSettings, streamingCallSettings, clientContext);
}
+ @Override
public
ServerStreamingCallable createServerStreamingCallable(
GrpcCallSettings grpcCallSettings,
ServerStreamingCallSettings streamingCallSettings,
ClientContext clientContext) {
- return GrpcCallableFactory.createServerStreamingCallable(
- grpcCallSettings, streamingCallSettings, clientContext);
+ ServerStreamingCallable defaultCallable =
+ GrpcCallableFactory.createServerStreamingCallable(
+ grpcCallSettings, streamingCallSettings, clientContext);
+ return new ExceptionTransformingServerStreamingCallable(
+ defaultCallable, new GoogleAdsExceptionTransformation());
}
+ @Override
public
ClientStreamingCallable createClientStreamingCallable(
GrpcCallSettings grpcCallSettings,
diff --git a/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformation.java b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformation.java
new file mode 100644
index 0000000000..4788cdbf03
--- /dev/null
+++ b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformation.java
@@ -0,0 +1,26 @@
+// Copyright 2020 Google LLC
+//
+// 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.ads.googleads.lib.callables;
+
+/** Represents a transformation between {@link Throwable}s. */
+public interface ExceptionTransformation {
+
+ /**
+ * Transforms an input throwable to an output throwable.
+ *
+ *
If no transformation is applied this must return the input throwable.
+ */
+ Throwable transform(Throwable throwable);
+}
diff --git a/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingServerStreamingCallable.java b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingServerStreamingCallable.java
new file mode 100644
index 0000000000..5ff36d0f07
--- /dev/null
+++ b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingServerStreamingCallable.java
@@ -0,0 +1,81 @@
+// Copyright 2020 Google LLC
+//
+// 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.ads.googleads.lib.callables;
+
+import com.google.api.gax.rpc.ApiCallContext;
+import com.google.api.gax.rpc.ApiException;
+import com.google.api.gax.rpc.ResponseObserver;
+import com.google.api.gax.rpc.ServerStreamingCallable;
+import com.google.api.gax.rpc.StreamController;
+
+/**
+ * Wrapper around a {@link ServerStreamingCallable} which invokes an {@link ExceptionTransformation}
+ * for {@link Throwable}s which occur on the stream.
+ *
+ *
NOTE: This class could be pushed into the gax library, as it is not specific to the Google Ads
+ * API.
+ */
+public class ExceptionTransformingServerStreamingCallable
+ extends ServerStreamingCallable {
+
+ private final ServerStreamingCallable innerCallable;
+ private final ExceptionTransformation exceptionTransformation;
+
+ public ExceptionTransformingServerStreamingCallable(
+ ServerStreamingCallable innerCallable,
+ ExceptionTransformation exceptionTransformation) {
+ this.innerCallable = innerCallable;
+ this.exceptionTransformation = exceptionTransformation;
+ }
+
+ @Override
+ public void call(
+ RequestT request, ResponseObserver responseObserver, ApiCallContext context) {
+ innerCallable.call(request, new ExceptionTransformingStreamObserver(responseObserver), context);
+ }
+
+ /** Provides a mechanism for transforming any exceptions which occur on the stream. */
+ private class ExceptionTransformingStreamObserver implements ResponseObserver {
+
+ private final ResponseObserver innerObserver;
+
+ public ExceptionTransformingStreamObserver(ResponseObserver innerObserver) {
+ this.innerObserver = innerObserver;
+ }
+
+ @Override
+ public void onStart(StreamController controller) {
+ innerObserver.onStart(controller);
+ }
+
+ @Override
+ public void onResponse(ResponseT response) {
+ innerObserver.onResponse(response);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ if (t instanceof ApiException) {
+ t = exceptionTransformation.transform(t);
+ }
+ innerObserver.onError(t);
+ }
+
+ @Override
+ public void onComplete() {
+ innerObserver.onComplete();
+ }
+ }
+}
diff --git a/google-ads/src/main/java/com/google/ads/googleads/lib/ExceptionTransformingCallable.java b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingUnaryCallable.java
similarity index 82%
rename from google-ads/src/main/java/com/google/ads/googleads/lib/ExceptionTransformingCallable.java
rename to google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingUnaryCallable.java
index 95f6b8394e..c13e65baaa 100644
--- a/google-ads/src/main/java/com/google/ads/googleads/lib/ExceptionTransformingCallable.java
+++ b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/ExceptionTransformingUnaryCallable.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.ads.googleads.lib;
+package com.google.ads.googleads.lib.callables;
import com.google.api.core.AbstractApiFuture;
import com.google.api.core.ApiFuture;
@@ -20,26 +20,24 @@
import com.google.api.core.ApiFutures;
import com.google.api.gax.grpc.GrpcCallContext;
import com.google.api.gax.rpc.ApiCallContext;
-import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.UnaryCallable;
import com.google.common.base.Preconditions;
import java.util.concurrent.CancellationException;
/**
- * NOTE: This class could be pushed into the gax library, as it is not specific to the Google Ads
+ * Wrapper around a {@link UnaryCallable} which invokes an {@link ExceptionTransformation} for
+ * {@link Throwable}s which occur on the stream.
+ *
+ *
NOTE: This class could be pushed into the gax library, as it is not specific to the Google Ads
* API.
*/
-public class ExceptionTransformingCallable
+public class ExceptionTransformingUnaryCallable
extends UnaryCallable {
- public interface ExceptionTransformation {
- Throwable transform(ApiException throwable);
- }
-
private final UnaryCallable callable;
private final ExceptionTransformation transformation;
- public ExceptionTransformingCallable(
+ public ExceptionTransformingUnaryCallable(
UnaryCallable callable, ExceptionTransformation transformation) {
this.callable = Preconditions.checkNotNull(callable);
this.transformation = transformation;
@@ -55,6 +53,7 @@ public ApiFuture futureCall(RequestT request, ApiCallContext inputCon
return transformingFuture;
}
+ /** Provides a mechanism to transform exceptions which occur on the inner callable. */
private class ExceptionTransformingFuture extends AbstractApiFuture
implements ApiFutureCallback {
private ApiFuture innerCallFuture;
@@ -79,8 +78,8 @@ public void onSuccess(ResponseT r) {
public void onFailure(Throwable throwable) {
if (throwable instanceof CancellationException && cancelled) {
// this just circled around, so ignore.
- } else if (throwable instanceof ApiException) {
- setException(transformation.transform((ApiException) throwable));
+ } else {
+ setException(transformation.transform(throwable));
}
}
}
diff --git a/google-ads/src/main/java/com/google/ads/googleads/lib/GoogleAdsExceptionTransformation.java b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/GoogleAdsExceptionTransformation.java
similarity index 62%
rename from google-ads/src/main/java/com/google/ads/googleads/lib/GoogleAdsExceptionTransformation.java
rename to google-ads/src/main/java/com/google/ads/googleads/lib/callables/GoogleAdsExceptionTransformation.java
index b596230ab5..9ca152c30d 100644
--- a/google-ads/src/main/java/com/google/ads/googleads/lib/GoogleAdsExceptionTransformation.java
+++ b/google-ads/src/main/java/com/google/ads/googleads/lib/callables/GoogleAdsExceptionTransformation.java
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.ads.googleads.lib;
+package com.google.ads.googleads.lib.callables;
+import com.google.ads.googleads.lib.BaseGoogleAdsException;
import com.google.ads.googleads.lib.catalog.GeneratedCatalog;
import com.google.ads.googleads.lib.catalog.Version;
import com.google.api.gax.rpc.ApiException;
@@ -23,20 +24,21 @@
* Transforms an ApiException into a GoogleAdsException whenever a binary GoogleAdsFailure message
* was sent in the RPC trailers.
*/
-public class GoogleAdsExceptionTransformation
- implements ExceptionTransformingCallable.ExceptionTransformation {
+public class GoogleAdsExceptionTransformation implements ExceptionTransformation {
private static final GeneratedCatalog catalog = GeneratedCatalog.getDefault();
@Override
- public Throwable transform(ApiException apiException) {
- for (Version version : catalog.getSupportedVersions()) {
- Optional extends BaseGoogleAdsException> result =
- version.getExceptionFactory().createGoogleAdsException(apiException);
- if (result.isPresent()) {
- return result.get();
+ public Throwable transform(Throwable input) {
+ if (ApiException.class.isAssignableFrom(input.getClass())) {
+ for (Version version : catalog.getSupportedVersions()) {
+ Optional extends BaseGoogleAdsException> result =
+ version.getExceptionFactory().createGoogleAdsException((ApiException) input);
+ if (result.isPresent()) {
+ return result.get();
+ }
}
}
- return apiException;
+ return input;
}
}
diff --git a/google-ads/src/test/java/com/google/ads/googleads/lib/GoogleAdsClientTest.java b/google-ads/src/test/java/com/google/ads/googleads/lib/GoogleAdsClientTest.java
index dcff1ff03d..ad5a8853aa 100644
--- a/google-ads/src/test/java/com/google/ads/googleads/lib/GoogleAdsClientTest.java
+++ b/google-ads/src/test/java/com/google/ads/googleads/lib/GoogleAdsClientTest.java
@@ -29,9 +29,13 @@
import com.google.ads.googleads.v5.errors.GoogleAdsError;
import com.google.ads.googleads.v5.errors.GoogleAdsException;
import com.google.ads.googleads.v5.errors.GoogleAdsFailure;
+import com.google.ads.googleads.v5.services.GoogleAdsRow;
import com.google.ads.googleads.v5.services.GoogleAdsServiceClient;
+import com.google.ads.googleads.v5.services.GoogleAdsServiceClient.SearchPagedResponse;
import com.google.ads.googleads.v5.services.MockGoogleAdsService;
import com.google.ads.googleads.v5.services.SearchGoogleAdsResponse;
+import com.google.ads.googleads.v5.services.SearchGoogleAdsStreamRequest;
+import com.google.ads.googleads.v5.services.SearchGoogleAdsStreamResponse;
import com.google.api.gax.grpc.GaxGrpcProperties;
import com.google.api.gax.grpc.GrpcStatusCode;
import com.google.api.gax.grpc.testing.LocalChannelProvider;
@@ -69,9 +73,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-/**
- * Tests for {@link GoogleAdsClient}.
- */
+/** Tests for {@link GoogleAdsClient}. */
@RunWith(Parameterized.class)
public class GoogleAdsClientTest {
@@ -84,12 +86,9 @@ public class GoogleAdsClientTest {
private static final MockGoogleAdsService mockService = new MockGoogleAdsService();
private static final MockServiceHelper mockServiceHelper =
new MockServiceHelper("fake-address", mockService);
- @Rule
- public TemporaryFolder folder = new TemporaryFolder();
- @Rule
- public ExpectedException thrown = ExpectedException.none();
- @Mock
- private ScheduledExecutorService executor;
+ @Rule public TemporaryFolder folder = new TemporaryFolder();
+ @Rule public ExpectedException thrown = ExpectedException.none();
+ @Mock private ScheduledExecutorService executor;
private Credentials fakeCredentials = new FakeCredential();
private LocalChannelProvider localChannelProvider;
private Properties testProperties;
@@ -101,7 +100,7 @@ public GoogleAdsClientTest(boolean enabledGeneratedCatalog) {
@Parameterized.Parameters
public static List