mirror of https://github.com/apache/jclouds.git
Merge pull request #1126 from jclouds/no-double-retry
don't double-retry j.u.c.TimeoutException
This commit is contained in:
commit
6cdec6aad0
|
@ -887,7 +887,7 @@ public class CloudServersAsyncClientTest extends BaseAsyncClientTest<CloudServer
|
|||
GetAuth provideGetAuth() {
|
||||
return new GetAuth(null) {
|
||||
@Override
|
||||
public Auth apply(Credentials in) {
|
||||
public Auth load(Credentials in) {
|
||||
return new ParseAuthTest().expected();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -116,10 +116,9 @@ import org.jclouds.cloudstack.features.ZoneClient;
|
|||
import org.jclouds.cloudstack.filters.AddSessionKeyAndJSessionIdToRequest;
|
||||
import org.jclouds.cloudstack.filters.AuthenticationFilter;
|
||||
import org.jclouds.cloudstack.filters.QuerySigner;
|
||||
import org.jclouds.cloudstack.functions.LoginWithPasswordCredentials;
|
||||
import org.jclouds.cloudstack.handlers.CloudStackErrorHandler;
|
||||
import org.jclouds.cloudstack.handlers.InvalidateSessionAndRetryOn401AndLogoutOnClose;
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||
import org.jclouds.cloudstack.loaders.LoginWithPasswordCredentials;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
|
@ -134,10 +133,8 @@ import org.jclouds.rest.RestContext;
|
|||
import org.jclouds.rest.config.RestClientModule;
|
||||
import org.jclouds.rest.internal.RestContextImpl;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
|
@ -269,24 +266,13 @@ public class CloudStackRestClientModule extends RestClientModule<CloudStackClien
|
|||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Function<Credentials, LoginResponse> makeSureFilterRetriesOnTimeout(
|
||||
LoginWithPasswordCredentials loginWithPasswordCredentials) {
|
||||
// we should retry on timeout exception logging in.
|
||||
return new RetryOnTimeOutExceptionFunction<Credentials, LoginResponse>(loginWithPasswordCredentials);
|
||||
}
|
||||
|
||||
// TODO: not sure we can action the timeout from loginresponse without extra code? modify default
|
||||
// accordingly
|
||||
// PROPERTY_SESSION_INTERVAL is default to 60 seconds
|
||||
@Provides
|
||||
@Singleton
|
||||
public LoadingCache<Credentials, LoginResponse> provideLoginResponseCache(
|
||||
Function<Credentials, LoginResponse> getLoginResponse,
|
||||
protected LoadingCache<Credentials, LoginResponse> provideLoginResponseCache(
|
||||
LoginWithPasswordCredentials getLoginResponse,
|
||||
@Named(Constants.PROPERTY_SESSION_INTERVAL) int seconds) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(
|
||||
CacheLoader.from(getLoginResponse));
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(getLoginResponse);
|
||||
}
|
||||
|
||||
// Temporary conversion of a cache to a supplier until there is a single-element cache
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.cloudstack.functions;
|
||||
package org.jclouds.cloudstack.loaders;
|
||||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static com.google.common.hash.Hashing.md5;
|
||||
|
@ -31,10 +31,10 @@ import org.jclouds.cloudstack.domain.LoginResponse;
|
|||
import org.jclouds.cloudstack.features.SessionClient;
|
||||
import org.jclouds.domain.Credentials;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
@Singleton
|
||||
public class LoginWithPasswordCredentials implements Function<Credentials, LoginResponse> {
|
||||
public class LoginWithPasswordCredentials extends CacheLoader<Credentials, LoginResponse> {
|
||||
private final SessionClient client;
|
||||
|
||||
@Inject
|
||||
|
@ -43,7 +43,7 @@ public class LoginWithPasswordCredentials implements Function<Credentials, Login
|
|||
}
|
||||
|
||||
@Override
|
||||
public LoginResponse apply(Credentials input) {
|
||||
public LoginResponse load(Credentials input) {
|
||||
String username = input.identity;
|
||||
String domain = ""; // empty = ROOT domain
|
||||
|
|
@ -29,10 +29,11 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.ComputeServiceContext;
|
||||
import org.jclouds.compute.config.BaseComputeServiceContextModule;
|
||||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier;
|
||||
import org.jclouds.ec2.compute.EC2ComputeService;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.loaders.RegionAndIdToImage;
|
||||
import org.jclouds.ec2.compute.suppliers.RegionAndNameToImageSupplier;
|
||||
|
@ -118,12 +119,7 @@ public class EC2ComputeServiceContextModule extends BaseComputeServiceContextMod
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// wrap in retry logic
|
||||
Supplier<Image> retryingSupplier = new RetryOnTimeOutExceptionSupplier<Image>(
|
||||
new SetAndThrowAuthorizationExceptionSupplier<Image>(rawSupplier, authException));
|
||||
|
||||
return retryingSupplier.get();
|
||||
return new SetAndThrowAuthorizationExceptionSupplier<Image>(rawSupplier, authException).get();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -30,7 +30,6 @@ import java.util.concurrent.TimeoutException;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
|
@ -47,8 +46,8 @@ import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
|
|||
import org.jclouds.location.suppliers.derived.ZoneIdsFromZoneIdToURIKeySet;
|
||||
import org.jclouds.location.suppliers.implicit.FirstRegion;
|
||||
import org.jclouds.location.suppliers.implicit.FirstZone;
|
||||
import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncApi;
|
||||
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
|
||||
import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncApi;
|
||||
import org.jclouds.openstack.keystone.v2_0.domain.Access;
|
||||
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials;
|
||||
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCredentials;
|
||||
|
@ -179,9 +178,7 @@ public class KeystoneAuthenticationModule extends AbstractModule {
|
|||
Map<String, Function<Credentials, Access>> authenticationMethods) {
|
||||
checkArgument(authenticationMethods.containsKey(credentialType), "credential type %s not in supported list: %s",
|
||||
credentialType, authenticationMethods.keySet());
|
||||
// regardless of how we authenticate, we should retry if there is a timeout exception logging
|
||||
// in.
|
||||
return new RetryOnTimeOutExceptionFunction<Credentials, Access>(authenticationMethods.get(credentialType));
|
||||
return authenticationMethods.get(credentialType);
|
||||
}
|
||||
|
||||
// TODO: what is the timeout of the session token? modify default accordingly
|
||||
|
|
|
@ -29,7 +29,6 @@ import java.util.concurrent.TimeoutException;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
|
@ -42,14 +41,12 @@ import org.jclouds.openstack.internal.Authentication;
|
|||
import org.jclouds.openstack.internal.OpenStackAuthAsyncClient;
|
||||
import org.jclouds.openstack.internal.OpenStackAuthClient;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
|
||||
/**
|
||||
|
@ -61,8 +58,6 @@ public class OpenStackAuthenticationModule extends AbstractModule {
|
|||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Function<Credentials, AuthenticationResponse>>() {
|
||||
}).to(GetAuthenticationResponse.class);
|
||||
// OpenStackAuthClient is used directly for filters and retry handlers, so let's bind it explicitly
|
||||
bindClientAndAsyncClient(binder(), OpenStackAuthClient.class, OpenStackAuthAsyncClient.class);
|
||||
install(new FactoryModuleBuilder().build(URIFromAuthenticationResponseForService.Factory.class));
|
||||
|
@ -85,33 +80,31 @@ public class OpenStackAuthenticationModule extends AbstractModule {
|
|||
}
|
||||
|
||||
@Singleton
|
||||
public static class GetAuthenticationResponse extends
|
||||
RetryOnTimeOutExceptionFunction<Credentials, AuthenticationResponse> {
|
||||
public static class GetAuthenticationResponse extends CacheLoader<Credentials, AuthenticationResponse> {
|
||||
private final OpenStackAuthClient client;
|
||||
|
||||
@Inject
|
||||
public GetAuthenticationResponse(final OpenStackAuthClient client) {
|
||||
super(new Function<Credentials, AuthenticationResponse>() {
|
||||
|
||||
@Override
|
||||
public AuthenticationResponse apply(Credentials input) {
|
||||
return client.authenticate(input.identity, input.credential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "authenticate()";
|
||||
}
|
||||
});
|
||||
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationResponse load(Credentials input) {
|
||||
return client.authenticate(input.identity, input.credential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "authenticate()";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public LoadingCache<Credentials, AuthenticationResponse> provideAuthenticationResponseCache(
|
||||
Function<Credentials, AuthenticationResponse> getAuthenticationResponse) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(
|
||||
CacheLoader.from(getAuthenticationResponse));
|
||||
GetAuthenticationResponse getAuthenticationResponse) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(getAuthenticationResponse);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.util.concurrent.TimeoutException;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
|
@ -43,14 +42,12 @@ import org.jclouds.openstack.keystone.v1_1.handlers.RetryOnRenew;
|
|||
import org.jclouds.openstack.keystone.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
|
||||
import org.jclouds.openstack.keystone.v1_1.suppliers.V1DefaultRegionIdSupplier;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.assistedinject.FactoryModuleBuilder;
|
||||
|
||||
/**
|
||||
|
@ -61,8 +58,6 @@ public class AuthenticationServiceModule extends AbstractModule {
|
|||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Function<Credentials, Auth>>() {
|
||||
}).to(GetAuth.class);
|
||||
// ServiceClient is used directly for filters and retry handlers, so let's bind it explicitly
|
||||
bindClientAndAsyncClient(binder(), AuthenticationClient.class, AuthenticationAsyncClient.class);
|
||||
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
|
||||
|
@ -88,30 +83,30 @@ public class AuthenticationServiceModule extends AbstractModule {
|
|||
}
|
||||
|
||||
@Singleton
|
||||
public static class GetAuth extends RetryOnTimeOutExceptionFunction<Credentials, Auth> {
|
||||
public static class GetAuth extends CacheLoader<Credentials, Auth> {
|
||||
|
||||
private final AuthenticationClient client;
|
||||
|
||||
@Inject
|
||||
public GetAuth(final AuthenticationClient client) {
|
||||
super(new Function<Credentials, Auth>() {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Auth apply(Credentials input) {
|
||||
return client.authenticate(input.identity, input.credential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "authenticate()";
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public Auth load(Credentials input) {
|
||||
return client.authenticate(input.identity, input.credential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "authenticate()";
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public LoadingCache<Credentials, Auth> provideAuthCache(Function<Credentials, Auth> getAuth) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(CacheLoader.from(getAuth));
|
||||
protected LoadingCache<Credentials, Auth> provideAuthCache(GetAuth getAuth) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS).build(getAuth);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -52,7 +52,7 @@ public class TestOpenStackAuthenticationModule extends OpenStackAuthenticationMo
|
|||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationResponse apply(Credentials input) {
|
||||
public AuthenticationResponse load(Credentials input) {
|
||||
return new AuthenticationResponse("authToken", ImmutableMap.<String, URI> of(
|
||||
AuthHeaders.SERVER_MANAGEMENT_URL, URI.create("http://endpoint/vapi-version"),
|
||||
AuthHeaders.STORAGE_URL, URI.create("http://storage")));
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.concurrent;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ForwardingObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RetryOnTimeOutExceptionFunction<K,V> extends ForwardingObject implements Function<K,V>{
|
||||
private final Function<K,V> delegate;
|
||||
|
||||
public RetryOnTimeOutExceptionFunction(Function<K,V> delegate) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
//TODO: backoff limited retry handler
|
||||
@Override
|
||||
public V apply(K key) {
|
||||
TimeoutException ex = null;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try {
|
||||
ex = null;
|
||||
return delegate().apply(key);
|
||||
} catch (Exception e) {
|
||||
if ((ex = Throwables2.getFirstThrowableOfType(e, TimeoutException.class)) != null)
|
||||
continue;
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
if (ex != null)
|
||||
throw propagate(ex);
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return delegate.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Function<K,V> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.concurrent;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RetryOnTimeOutExceptionSupplier<T> implements Supplier<T> {
|
||||
private final Supplier<T> delegate;
|
||||
|
||||
public RetryOnTimeOutExceptionSupplier(Supplier<T> delegate) {
|
||||
this.delegate = checkNotNull(delegate, "delegate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
TimeoutException ex = null;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
try {
|
||||
ex = null;
|
||||
return delegate.get();
|
||||
} catch (Exception e) {
|
||||
if ((ex = Throwables2.getFirstThrowableOfType(e, TimeoutException.class)) != null)
|
||||
continue;
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
if (ex != null)
|
||||
propagate(ex);
|
||||
assert false;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RetryOnTimeOutExceptionSupplier(" + delegate + ")";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.concurrent;
|
||||
|
||||
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.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* Tests behavior of RetryOnTimeOutExceptionFunction
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true, testName = "RetryOnTimeOutExceptionFunctionTest")
|
||||
public class RetryOnTimeOutExceptionFunctionTest {
|
||||
ExecutorService executorService = MoreExecutors.sameThreadExecutor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetThrowsOriginalExceptionButRetriesOnTimeoutException() throws InterruptedException, ExecutionException {
|
||||
Function<String, String> delegate = createMock(Function.class);
|
||||
TimeoutException timeout = createMock(TimeoutException.class);
|
||||
RuntimeException throwable = new RuntimeException(timeout);
|
||||
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
expect(timeout.getCause()).andReturn(null).anyTimes();
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
|
||||
replay(delegate);
|
||||
replay(timeout);
|
||||
|
||||
RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
|
||||
delegate);
|
||||
try {
|
||||
supplier.apply("baz");
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(e.getCause(), timeout);
|
||||
}
|
||||
|
||||
verify(delegate);
|
||||
verify(timeout);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetAllowsTwoFailuresOnTimeoutException() throws InterruptedException, ExecutionException {
|
||||
Function<String, String> delegate = createMock(Function.class);
|
||||
TimeoutException timeout = createMock(TimeoutException.class);
|
||||
RuntimeException throwable = new RuntimeException(timeout);
|
||||
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
expect(timeout.getCause()).andReturn(null).anyTimes();
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
expect(delegate.apply("baz")).andReturn("foo");
|
||||
|
||||
replay(delegate);
|
||||
replay(timeout);
|
||||
|
||||
RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
|
||||
delegate);
|
||||
assertEquals(supplier.apply("baz"), "foo");
|
||||
|
||||
verify(delegate);
|
||||
verify(timeout);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetAllowsNoFailuresOnOtherExceptions() throws InterruptedException, ExecutionException {
|
||||
Function<String, String> delegate = createMock(Function.class);
|
||||
AuthorizationException auth = createMock(AuthorizationException.class);
|
||||
RuntimeException throwable = new RuntimeException(auth);
|
||||
|
||||
expect(delegate.apply("baz")).andThrow(throwable);
|
||||
expect(auth.getCause()).andReturn(null).anyTimes();
|
||||
|
||||
|
||||
replay(delegate);
|
||||
replay(auth);
|
||||
|
||||
RetryOnTimeOutExceptionFunction<String, String> supplier = new RetryOnTimeOutExceptionFunction<String, String>(
|
||||
delegate);
|
||||
|
||||
try {
|
||||
supplier.apply("baz");
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(e.getCause(), auth);
|
||||
}
|
||||
|
||||
verify(delegate);
|
||||
verify(auth);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds 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.jclouds.concurrent;
|
||||
|
||||
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.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* Tests behavior of RetryOnTimeOutExceptionSupplier
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit")
|
||||
public class RetryOnTimeOutExceptionSupplierTest {
|
||||
ExecutorService executorService = MoreExecutors.sameThreadExecutor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetThrowsOriginalExceptionButRetriesOnTimeoutException() throws InterruptedException, ExecutionException {
|
||||
Supplier<String> delegate = createMock(Supplier.class);
|
||||
TimeoutException timeout = createMock(TimeoutException.class);
|
||||
RuntimeException throwable = new RuntimeException(timeout);
|
||||
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
expect(timeout.getCause()).andReturn(null).anyTimes();
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
|
||||
replay(delegate);
|
||||
replay(timeout);
|
||||
|
||||
RetryOnTimeOutExceptionSupplier<String> supplier = new RetryOnTimeOutExceptionSupplier<String>(
|
||||
delegate);
|
||||
try {
|
||||
supplier.get();
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(e.getCause(), timeout);
|
||||
}
|
||||
|
||||
verify(delegate);
|
||||
verify(timeout);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetAllowsTwoFailuresOnTimeoutException() throws InterruptedException, ExecutionException {
|
||||
Supplier<String> delegate = createMock(Supplier.class);
|
||||
TimeoutException timeout = createMock(TimeoutException.class);
|
||||
RuntimeException throwable = new RuntimeException(timeout);
|
||||
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
expect(timeout.getCause()).andReturn(null).anyTimes();
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
expect(delegate.get()).andReturn("foo");
|
||||
|
||||
replay(delegate);
|
||||
replay(timeout);
|
||||
|
||||
RetryOnTimeOutExceptionSupplier<String> supplier = new RetryOnTimeOutExceptionSupplier<String>(
|
||||
delegate);
|
||||
assertEquals(supplier.get(), "foo");
|
||||
|
||||
verify(delegate);
|
||||
verify(timeout);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testGetAllowsNoFailuresOnOtherExceptions() throws InterruptedException, ExecutionException {
|
||||
Supplier<String> delegate = createMock(Supplier.class);
|
||||
AuthorizationException auth = createMock(AuthorizationException.class);
|
||||
RuntimeException throwable = new RuntimeException(auth);
|
||||
|
||||
expect(delegate.get()).andThrow(throwable);
|
||||
expect(auth.getCause()).andReturn(null).anyTimes();
|
||||
|
||||
|
||||
replay(delegate);
|
||||
replay(auth);
|
||||
|
||||
RetryOnTimeOutExceptionSupplier<String> supplier = new RetryOnTimeOutExceptionSupplier<String>(
|
||||
delegate);
|
||||
|
||||
try {
|
||||
supplier.get();
|
||||
fail();
|
||||
} catch (RuntimeException e) {
|
||||
assertEquals(e.getCause(), auth);
|
||||
}
|
||||
|
||||
verify(delegate);
|
||||
verify(auth);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
package org.jclouds.vcloud.director.v1_5.config;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -26,8 +27,6 @@ import java.util.Map;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionFunction;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
|
@ -84,10 +83,10 @@ import org.jclouds.vcloud.director.v1_5.features.admin.GroupApi;
|
|||
import org.jclouds.vcloud.director.v1_5.features.admin.GroupAsyncApi;
|
||||
import org.jclouds.vcloud.director.v1_5.features.admin.UserApi;
|
||||
import org.jclouds.vcloud.director.v1_5.features.admin.UserAsyncApi;
|
||||
import org.jclouds.vcloud.director.v1_5.functions.LoginUserInOrgWithPassword;
|
||||
import org.jclouds.vcloud.director.v1_5.functions.href.ResolveEntity;
|
||||
import org.jclouds.vcloud.director.v1_5.handlers.InvalidateSessionAndRetryOn401AndLogoutOnClose;
|
||||
import org.jclouds.vcloud.director.v1_5.handlers.VCloudDirectorErrorHandler;
|
||||
import org.jclouds.vcloud.director.v1_5.loaders.LoginUserInOrgWithPassword;
|
||||
import org.jclouds.vcloud.director.v1_5.loaders.ResolveEntity;
|
||||
import org.jclouds.vcloud.director.v1_5.login.SessionApi;
|
||||
import org.jclouds.vcloud.director.v1_5.login.SessionAsyncApi;
|
||||
import org.jclouds.vcloud.director.v1_5.user.VCloudDirectorApi;
|
||||
|
@ -96,7 +95,6 @@ import org.jclouds.vcloud.director.v1_5.user.VCloudDirectorAsyncApi;
|
|||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Provides;
|
||||
|
@ -211,36 +209,18 @@ public class VCloudDirectorRestClientModule extends RestClientModule<VCloudDirec
|
|||
}, in);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Function<String, Entity> makeSureResolveEntityRetriesOnTimeout(ResolveEntity resolveEntity) {
|
||||
// we should retry on timeout exception logging in.
|
||||
return new RetryOnTimeOutExceptionFunction<String, Entity>(resolveEntity);
|
||||
LoadingCache<String, Entity> resolveEntityCache(ResolveEntity loader, @Named(PROPERTY_SESSION_INTERVAL) int seconds) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(loader);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public LoadingCache<String, Entity> resolveEntityCache(Function<String, Entity> getEntity,
|
||||
@Named(Constants.PROPERTY_SESSION_INTERVAL) int seconds) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(CacheLoader.from(getEntity));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Function<Credentials, SessionWithToken> makeSureFilterRetriesOnTimeout(
|
||||
LoginUserInOrgWithPassword loginWithPasswordCredentials) {
|
||||
// we should retry on timeout exception logging in.
|
||||
return new RetryOnTimeOutExceptionFunction<Credentials, SessionWithToken>(loginWithPasswordCredentials);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public LoadingCache<Credentials, SessionWithToken> provideSessionWithTokenCache(
|
||||
Function<Credentials, SessionWithToken> getSessionWithToken,
|
||||
@Named(Constants.PROPERTY_SESSION_INTERVAL) int seconds) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(
|
||||
CacheLoader.from(getSessionWithToken));
|
||||
LoadingCache<Credentials, SessionWithToken> provideSessionWithTokenCache(LoginUserInOrgWithPassword loader,
|
||||
@Named(PROPERTY_SESSION_INTERVAL) int seconds) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(seconds, TimeUnit.SECONDS).build(loader);
|
||||
}
|
||||
|
||||
// Temporary conversion of a cache to a supplier until there is a single-element cache
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.vcloud.director.v1_5.functions;
|
||||
package org.jclouds.vcloud.director.v1_5.loaders;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
|
@ -28,11 +28,11 @@ import org.jclouds.vcloud.director.v1_5.annotations.Login;
|
|||
import org.jclouds.vcloud.director.v1_5.domain.SessionWithToken;
|
||||
import org.jclouds.vcloud.director.v1_5.login.SessionApi;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
@Singleton
|
||||
public class LoginUserInOrgWithPassword implements Function<Credentials, SessionWithToken> {
|
||||
public class LoginUserInOrgWithPassword extends CacheLoader<Credentials, SessionWithToken> {
|
||||
private final SessionApi api;
|
||||
private final Supplier<URI> loginUrl;
|
||||
|
||||
|
@ -43,11 +43,10 @@ public class LoginUserInOrgWithPassword implements Function<Credentials, Session
|
|||
}
|
||||
|
||||
@Override
|
||||
public SessionWithToken apply(Credentials input) {
|
||||
public SessionWithToken load(Credentials input) {
|
||||
String user = input.identity.substring(0, input.identity.lastIndexOf('@'));
|
||||
String org = input.identity.substring(input.identity.lastIndexOf('@') + 1);
|
||||
String password = input.credential;
|
||||
|
||||
return api.loginUserInOrgWithPassword(loginUrl.get(), user, org, password);
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.vcloud.director.v1_5.functions.href;
|
||||
package org.jclouds.vcloud.director.v1_5.loaders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
|
@ -26,10 +26,10 @@ import javax.inject.Singleton;
|
|||
import org.jclouds.vcloud.director.v1_5.domain.Entity;
|
||||
import org.jclouds.vcloud.director.v1_5.user.VCloudDirectorApi;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
|
||||
@Singleton
|
||||
public class ResolveEntity implements Function<String, Entity> {
|
||||
public class ResolveEntity extends CacheLoader<String, Entity> {
|
||||
private final VCloudDirectorApi api;
|
||||
|
||||
@Inject
|
||||
|
@ -38,7 +38,7 @@ public class ResolveEntity implements Function<String, Entity> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Entity apply(String input) {
|
||||
public Entity load(String input) {
|
||||
return api.resolveEntity(checkNotNull(input, "urn"));
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ import org.jclouds.compute.config.BaseComputeServiceContextModule;
|
|||
import org.jclouds.compute.domain.Image;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier;
|
||||
import org.jclouds.ec2.compute.config.EC2BindComputeStrategiesByClass;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.functions.RunningInstanceToNodeMetadata;
|
||||
|
@ -147,12 +146,7 @@ public class AWSEC2ComputeServiceContextModule extends BaseComputeServiceContext
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// wrap in retry logic
|
||||
Supplier<Image> retryingSupplier = new RetryOnTimeOutExceptionSupplier<Image>(
|
||||
new SetAndThrowAuthorizationExceptionSupplier<Image>(rawSupplier, authException));
|
||||
|
||||
return retryingSupplier.get();
|
||||
return new SetAndThrowAuthorizationExceptionSupplier<Image>(rawSupplier, authException).get();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue