blob: c487157a798e1565323d480663891d4d530aa621 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.beam.examples.complete.game.injector;
import static org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkNotNull;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.HttpBackOffIOExceptionHandler;
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.client.util.Sleeper;
import java.util.logging.Logger;
/**
* RetryHttpInitializerWrapper will automatically retry upon RPC failures, preserving the
* auto-refresh behavior of the Google Credentials.
*/
public class RetryHttpInitializerWrapper implements HttpRequestInitializer {
/** A private logger. */
private static final Logger LOG = Logger.getLogger(RetryHttpInitializerWrapper.class.getName());
/** One minutes in miliseconds. */
private static final int ONEMINITUES = 60000;
/**
* Intercepts the request for filling in the "Authorization" header field, as well as recovering
* from certain unsuccessful error codes wherein the Credential must refresh its token for a
* retry.
*/
private final Credential wrappedCredential;
/** A sleeper; you can replace it with a mock in your test. */
private final Sleeper sleeper;
/**
* A constructor.
*
* @param wrappedCredential Credential which will be wrapped and used for providing auth header.
*/
public RetryHttpInitializerWrapper(final Credential wrappedCredential) {
this(wrappedCredential, Sleeper.DEFAULT);
}
/**
* A protected constructor only for testing.
*
* @param wrappedCredential Credential which will be wrapped and used for providing auth header.
* @param sleeper Sleeper for easy testing.
*/
RetryHttpInitializerWrapper(final Credential wrappedCredential, final Sleeper sleeper) {
this.wrappedCredential = checkNotNull(wrappedCredential);
this.sleeper = sleeper;
}
/** Initializes the given request. */
@Override
public final void initialize(final HttpRequest request) {
request.setReadTimeout(2 * ONEMINITUES); // 2 minutes read timeout
final HttpUnsuccessfulResponseHandler backoffHandler =
new HttpBackOffUnsuccessfulResponseHandler(new ExponentialBackOff()).setSleeper(sleeper);
request.setInterceptor(wrappedCredential);
request.setUnsuccessfulResponseHandler(
(request1, response, supportsRetry) -> {
if (wrappedCredential.handleResponse(request1, response, supportsRetry)) {
// If credential decides it can handle it, the return code or message indicated
// something specific to authentication, and no backoff is desired.
return true;
} else if (backoffHandler.handleResponse(request1, response, supportsRetry)) {
// Otherwise, we defer to the judgement of our internal backoff handler.
LOG.info("Retrying " + request1.getUrl().toString());
return true;
} else {
return false;
}
});
request.setIOExceptionHandler(
new HttpBackOffIOExceptionHandler(new ExponentialBackOff()).setSleeper(sleeper));
}
}