mirror of https://github.com/apache/jclouds.git
Merge pull request #1260 from jclouds/sync-http
Synchronous commands now use calling thread
This commit is contained in:
commit
9f7507b1e8
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.atmos;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
@ -69,10 +67,6 @@ public class AtmosApiMetadata extends BaseRestApiMetadata {
|
|||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_REGIONS, "DEFAULT");
|
||||
properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "X-Object-Meta-");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AtmosClient.createFile", MINUTES.toMillis(10) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AtmosClient.updateFile", MINUTES.toMillis(10) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AtmosClient.readFile", MINUTES.toMillis(10) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,9 @@ import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
|
@ -46,7 +47,7 @@ import com.google.common.reflect.Invokable;
|
|||
*/
|
||||
@Singleton
|
||||
public class AtmosBlobRequestSigner implements BlobRequestSigner {
|
||||
private final RestAnnotationProcessor processor;
|
||||
private final Function<Invocation, HttpRequest> processor;
|
||||
private final BlobToObject blobToObject;
|
||||
private final BlobToHttpGetOptions blob2ObjectGetOptions;
|
||||
|
||||
|
@ -55,7 +56,7 @@ public class AtmosBlobRequestSigner implements BlobRequestSigner {
|
|||
private final Invokable<?, ?> createMethod;
|
||||
|
||||
@Inject
|
||||
public AtmosBlobRequestSigner(RestAnnotationProcessor processor, BlobToObject blobToObject,
|
||||
public AtmosBlobRequestSigner(Function<Invocation, HttpRequest> processor, BlobToObject blobToObject,
|
||||
BlobToHttpGetOptions blob2ObjectGetOptions) throws SecurityException, NoSuchMethodException {
|
||||
this.processor = checkNotNull(processor, "processor");
|
||||
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
|
||||
|
|
|
@ -24,27 +24,32 @@ import static com.google.common.util.concurrent.Futures.immediateFuture;
|
|||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.blobstore.KeyAlreadyExistsException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class EndpointIfAlreadyExists implements FutureFallback<URI>, InvocationContext<EndpointIfAlreadyExists> {
|
||||
public class EndpointIfAlreadyExists implements Fallback<URI>, InvocationContext<EndpointIfAlreadyExists> {
|
||||
|
||||
private URI endpoint;
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URI> create(Throwable t) {
|
||||
public ListenableFuture<URI> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof KeyAlreadyExistsException) {
|
||||
return immediateFuture(endpoint);
|
||||
return endpoint;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
|
|
|
@ -35,24 +35,24 @@ import org.testng.annotations.Test;
|
|||
public class EndpointIfAlreadyExistsTest {
|
||||
|
||||
@Test
|
||||
public void testFoundIsNullWhenEndpointNotSet() {
|
||||
public void testFoundIsNullWhenEndpointNotSet() throws Exception {
|
||||
assertNull(getUnchecked(new EndpointIfAlreadyExists().create(new KeyAlreadyExistsException())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFoundIsEndpointWhenSet() {
|
||||
public void testFoundIsEndpointWhenSet() throws Exception {
|
||||
assertEquals(
|
||||
getUnchecked(new EndpointIfAlreadyExists().setEndpoint(URI.create("foo")).create(
|
||||
new KeyAlreadyExistsException())), URI.create("foo"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testNotFoundPropagates() {
|
||||
public void testNotFoundPropagates() throws Exception {
|
||||
new EndpointIfAlreadyExists().create(new RuntimeException());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullIsBad() {
|
||||
public void testNullIsBad() throws Exception {
|
||||
new EndpointIfAlreadyExists().create(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.cloudfiles;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -65,7 +62,6 @@ public class CloudFilesApiMetadata extends SwiftApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = SwiftApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "OpenStackAuthClient.authenticate", SECONDS.toMillis(30) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.cloudservers;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -63,8 +60,6 @@ public class CloudServersApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "OpenStackAuthClient.authenticate", SECONDS.toMillis(30) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.cloudsigma;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.cloudsigma.reference.CloudSigmaConstants.PROPERTY_VNC_PASSWORD;
|
||||
import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
@ -63,8 +61,6 @@ public class CloudSigmaApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "CloudSigmaClient.cloneDrive", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_VNC_PASSWORD, "IL9vs34d");
|
||||
// passwords are set post-boot, so auth failures are possible
|
||||
// from a race condition applying the password set script
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.cloudstack;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -60,9 +58,6 @@ public class CloudStackApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AddressClient.disassociateIPAddress", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "NATClient.enableStaticNATForVirtualMachine", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty("jclouds.ssh.max-retries", "7");
|
||||
properties.setProperty("jclouds.ssh.retry-auth", "true");
|
||||
return properties;
|
||||
|
|
|
@ -20,11 +20,11 @@ package org.jclouds.cloudstack.functions;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.Fallbacks.valOnNotFoundOr404;
|
||||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
|
||||
import org.jclouds.Fallbacks;
|
||||
import org.jclouds.Fallback;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class CloudStackFallbacks {
|
||||
|
@ -35,14 +35,19 @@ public final class CloudStackFallbacks {
|
|||
* CloudStack is currently sending 431 errors with the text "Unable to find account owner for ip ". In this case, we
|
||||
* have to ignore as there's no means for us to avoid the problem, or action to take.
|
||||
*/
|
||||
public static final class VoidOnNotFoundOr404OrUnableToFindAccountOwner implements FutureFallback<Void> {
|
||||
public static final class VoidOnNotFoundOr404OrUnableToFindAccountOwner implements Fallback<Void> {
|
||||
@Override
|
||||
public ListenableFuture<Void> create(final Throwable t) {
|
||||
public ListenableFuture<Void> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void createOrPropagate(Throwable t) throws Exception {
|
||||
IllegalStateException e = getFirstThrowableOfType(checkNotNull(t, "throwable"), IllegalStateException.class);
|
||||
if (e != null && e.getMessage().indexOf("Unable to find account owner for") != -1) {
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
} else {
|
||||
return Fallbacks.valOnNotFoundOr404(null, t);
|
||||
return valOnNotFoundOr404(null, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.cloudwatch;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
|
||||
|
@ -59,7 +57,6 @@ public class CloudWatchApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.ec2;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_DELIMITER;
|
||||
|
@ -81,8 +79,6 @@ public class EC2ApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ec2:DescribeImages", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
properties.setProperty(PROPERTY_EC2_AMI_OWNERS, "*");
|
||||
|
|
|
@ -23,24 +23,29 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class EC2Fallbacks {
|
||||
private EC2Fallbacks() {
|
||||
}
|
||||
|
||||
public static final class VoidOnVolumeAvailable implements FutureFallback<Object> {
|
||||
public static final class VoidOnVolumeAvailable implements Fallback<Void> {
|
||||
@Override
|
||||
public ListenableFuture<Object> create(final Throwable t) {
|
||||
public ListenableFuture<Void> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof AWSResponseException) {
|
||||
AWSResponseException e = AWSResponseException.class.cast(t);
|
||||
if (Predicates.in(ImmutableSet.of("IncorrectState", "available")).apply(e.getError().getCode()))
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.elasticstack;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.elasticstack.reference.ElasticStackConstants.PROPERTY_VNC_PASSWORD;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
|
@ -63,10 +61,6 @@ public class ElasticStackApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ElasticStackClient.startServer", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ElasticStackClient.createDrive", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ElasticStackClient.createAndStartServer", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty(PROPERTY_VNC_PASSWORD, "IL9vs34d");
|
||||
// passwords are set post-boot, so auth failures are possible
|
||||
// from a race condition applying the password set script
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.cinder.v1;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
|
@ -66,7 +64,6 @@ public class CinderApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.BLOCK_STORAGE);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
return properties;
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.keystone.v2_0;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
|
@ -66,8 +63,6 @@ public class KeystoneApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ExtensionApi", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.IDENTITY);
|
||||
return properties;
|
||||
|
|
|
@ -18,27 +18,33 @@
|
|||
*/
|
||||
package org.jclouds.openstack.keystone.v2_0;
|
||||
|
||||
import org.jclouds.Fallbacks;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.Fallbacks.valOnNotFoundOr404;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
|
||||
import org.jclouds.openstack.v2_0.domain.Link;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class KeystoneFallbacks {
|
||||
private KeystoneFallbacks() {
|
||||
}
|
||||
|
||||
public static final class EmptyPaginatedCollectionOnNotFoundOr404 implements
|
||||
FutureFallback<PaginatedCollection<Object>> {
|
||||
public static final class EmptyPaginatedCollectionOnNotFoundOr404 implements Fallback<PaginatedCollection<Object>> {
|
||||
private static final PaginatedCollection<Object> EMPTY = new PaginatedCollection<Object>(
|
||||
ImmutableSet.<Object> of(), ImmutableSet.<Link> of()) {
|
||||
};
|
||||
|
||||
@Override
|
||||
public ListenableFuture<PaginatedCollection<Object>> create(Throwable t) {
|
||||
return Fallbacks.valOnNotFoundOr404(EMPTY, t);
|
||||
public ListenableFuture<PaginatedCollection<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginatedCollection<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(EMPTY, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.nova.v2_0;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
import static org.jclouds.openstack.nova.v2_0.config.NovaProperties.AUTO_ALLOCATE_FLOATING_IPS;
|
||||
|
@ -72,8 +70,6 @@ public class NovaApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ServerApi.create", MINUTES.toMillis(10) + "");
|
||||
// auth fail can happen while cloud-init applies keypair updates
|
||||
properties.setProperty("jclouds.ssh.max-retries", "7");
|
||||
properties.setProperty("jclouds.ssh.retry-auth", "true");
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudloadbalancers;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
@ -67,7 +65,6 @@ public class CloudLoadBalancersApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.LOAD_BALANCERS);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CloudIdentityCredentialTypes.API_KEY_CREDENTIALS);
|
||||
return properties;
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
*/
|
||||
package org.jclouds.s3;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||
import static org.jclouds.Constants.PROPERTY_RELAX_HOSTNAME;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.DIRECTORY_SUFFIX_FOLDER;
|
||||
|
@ -84,11 +82,6 @@ public class S3ApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
|
||||
// 512KB/s for max size of 5GB
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "s3:GetObject", SECONDS.toMillis(5242880 / 512) + "");
|
||||
// 128KB/s for max size of 5GB; applies also to copy object, upload part
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "s3:PutObject", SECONDS.toMillis(5242880 / 128) + "");
|
||||
properties.setProperty(PROPERTY_API_VERSION, S3AsyncClient.VERSION);
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, S3Headers.DEFAULT_AMAZON_HEADERTAG);
|
||||
|
|
|
@ -25,24 +25,29 @@ import static com.google.common.util.concurrent.Futures.immediateFuture;
|
|||
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
|
||||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class S3Fallbacks {
|
||||
private S3Fallbacks() {
|
||||
}
|
||||
|
||||
public static final class TrueOn404OrNotFoundFalseOnIllegalState implements FutureFallback<Boolean> {
|
||||
public static final class TrueOn404OrNotFoundFalseOnIllegalState implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(final Throwable t) {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (getFirstThrowableOfType(checkNotNull(t, "throwable"), IllegalStateException.class) != null)
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
if (getFirstThrowableOfType(t, ContainerNotFoundException.class) != null)
|
||||
return immediateFuture(true);
|
||||
return true;
|
||||
if (returnValueOnCodeOrNull(t, true, equalTo(404)) != null)
|
||||
return immediateFuture(true);
|
||||
return true;
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,20 +26,20 @@ import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.s3.S3Client;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class FalseIfBucketAlreadyOwnedByYouOrOperationAbortedWhenBucketExists implements FutureFallback<Boolean>,
|
||||
public class FalseIfBucketAlreadyOwnedByYouOrOperationAbortedWhenBucketExists implements Fallback<Boolean>,
|
||||
InvocationContext<FalseIfBucketAlreadyOwnedByYouOrOperationAbortedWhenBucketExists> {
|
||||
|
||||
private final S3Client client;
|
||||
|
@ -51,14 +51,19 @@ public class FalseIfBucketAlreadyOwnedByYouOrOperationAbortedWhenBucketExists im
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(final Throwable t) {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
AWSResponseException exception = getFirstThrowableOfType(checkNotNull(t, "throwable"), AWSResponseException.class);
|
||||
if (exception != null && exception.getError() != null && exception.getError().getCode() != null) {
|
||||
String code = exception.getError().getCode();
|
||||
if (code.equals("BucketAlreadyOwnedByYou"))
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
else if (code.equals("OperationAborted") && bucket != null && client.bucketExists(bucket))
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.sqs;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_MAX_RETRIES;
|
||||
|
@ -63,9 +61,6 @@ public class SQSApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
// this will gracefully attempt to resolve name issues
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "sqs:CreateQueue", SECONDS.toMillis(61) + "");
|
||||
properties.setProperty(CREATE_QUEUE_MAX_RETRIES, "60");
|
||||
properties.setProperty(CREATE_QUEUE_RETRY_INTERVAL, "1000");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.sts;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
|
||||
|
@ -27,9 +25,9 @@ import java.net.URI;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.sts.config.STSRestClientModule;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||
import org.jclouds.sts.config.STSRestClientModule;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
|
@ -59,7 +57,6 @@ public class STSApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.swift;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
@ -67,12 +64,6 @@ public class SwiftApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(2) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "OpenStackAuthClient.authenticate", SECONDS.toMillis(10) + "");
|
||||
// TODO: value was randomly copied from S3: 512KB/s for max size of 5GB
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "CommonSwiftClient.getObject", SECONDS.toMillis(5242880 / 512) + "");
|
||||
// TODO: value was randomly copied from S3: 128KB/s for max size of 5GB
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "CommonSwiftClient.putObject", SECONDS.toMillis(5242880 / 128) + "");
|
||||
properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "X-Object-Meta-");
|
||||
properties.setProperty(PROPERTY_REGIONS, "DEFAULT");
|
||||
return properties;
|
||||
|
|
|
@ -25,20 +25,26 @@ import static com.google.common.util.concurrent.Futures.immediateFuture;
|
|||
import static org.jclouds.http.HttpUtils.contains404;
|
||||
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import org.jclouds.Fallback;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class SwiftFallbacks {
|
||||
private SwiftFallbacks() {
|
||||
}
|
||||
|
||||
public static final class TrueOn404FalseOn409 implements FutureFallback<Boolean> {
|
||||
public static final class TrueOn404FalseOn409 implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(final Throwable t) {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (contains404(checkNotNull(t, "throwable")))
|
||||
return immediateFuture(true);
|
||||
return true;
|
||||
if (returnValueOnCodeOrNull(t, false, equalTo(409)) != null)
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,8 @@ import org.jclouds.openstack.swift.TemporaryUrlKey;
|
|||
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -64,7 +63,7 @@ import com.google.inject.Provider;
|
|||
@Singleton
|
||||
public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRequestSigner {
|
||||
|
||||
private final RestAnnotationProcessor processor;
|
||||
private final Function<Invocation, HttpRequest> processor;
|
||||
private final Crypto crypto;
|
||||
|
||||
private final Provider<Long> unixEpochTimestampProvider;
|
||||
|
@ -86,8 +85,9 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
|
|||
@Inject
|
||||
protected SwiftBlobSigner(BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto,
|
||||
@TimeStamp Provider<Long> unixEpochTimestampProvider,
|
||||
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier, RestAnnotationProcessor processor,
|
||||
Class<T> ownerType) throws SecurityException, NoSuchMethodException {
|
||||
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier,
|
||||
Function<Invocation, HttpRequest> processor, Class<T> ownerType) throws SecurityException,
|
||||
NoSuchMethodException {
|
||||
this.processor = checkNotNull(processor, "processor");
|
||||
this.crypto = checkNotNull(crypto, "crypto");
|
||||
|
||||
|
@ -112,8 +112,7 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
|
|||
public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
|
||||
checkNotNull(container, "container");
|
||||
checkNotNull(name, "name");
|
||||
GeneratedHttpRequest request = processor.apply(Invocation.create(getMethod,
|
||||
ImmutableList.<Object> of(container, name)));
|
||||
HttpRequest request = processor.apply(Invocation.create(getMethod, ImmutableList.<Object> of(container, name)));
|
||||
return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
|
||||
}
|
||||
|
||||
|
@ -137,7 +136,7 @@ public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRe
|
|||
public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
|
||||
checkNotNull(container, "container");
|
||||
checkNotNull(blob, "blob");
|
||||
GeneratedHttpRequest request = processor.apply(Invocation.create(createMethod,
|
||||
HttpRequest request = processor.apply(Invocation.create(createMethod,
|
||||
ImmutableList.<Object> of(container, blobToObject.apply(blob))));
|
||||
return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.vcloud;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_DEFAULT_FENCEMODE;
|
||||
|
@ -69,9 +67,6 @@ public class VCloudApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "VCloudLoginClient.login", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "VCloudVersionsClient.getSupportedVersions", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_VCLOUD_VERSION_SCHEMA, "1");
|
||||
properties.setProperty(PROPERTY_VCLOUD_XML_NAMESPACE,
|
||||
String.format("http://www.vmware.com/vcloud/v${%s}", PROPERTY_VCLOUD_VERSION_SCHEMA));
|
||||
|
|
|
@ -23,20 +23,20 @@ import static com.google.common.base.Throwables.propagate;
|
|||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.http.HttpUtils.contains404;
|
||||
|
||||
import org.jclouds.blobstore.ContainerNotFoundException;
|
||||
import org.jclouds.blobstore.KeyNotFoundException;
|
||||
import org.jclouds.Fallback;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class BlobStoreFallbacks {
|
||||
private BlobStoreFallbacks() {
|
||||
}
|
||||
|
||||
public static final class ThrowContainerNotFoundOn404 implements FutureFallback<Object> {
|
||||
public static final class ThrowContainerNotFoundOn404 implements Fallback<Object> {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) {
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
if (contains404(checkNotNull(t, "throwable")))
|
||||
throw new ContainerNotFoundException(t);
|
||||
throw propagate(t);
|
||||
|
@ -44,10 +44,12 @@ public final class BlobStoreFallbacks {
|
|||
|
||||
}
|
||||
|
||||
public static final class ThrowKeyNotFoundOn404 implements FutureFallback<Object> {
|
||||
public static final class ThrowKeyNotFoundOn404 implements Fallback<Object> {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) {
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
if (contains404(checkNotNull(t, "throwable")))
|
||||
throw new KeyNotFoundException(t);
|
||||
throw propagate(t);
|
||||
|
@ -55,45 +57,53 @@ public final class BlobStoreFallbacks {
|
|||
|
||||
}
|
||||
|
||||
public static final class FalseOnContainerNotFound implements FutureFallback<Boolean> {
|
||||
public static final class FalseOnContainerNotFound implements Fallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof ContainerNotFoundException) {
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class FalseOnKeyNotFound implements FutureFallback<Boolean> {
|
||||
public static final class FalseOnKeyNotFound implements Fallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof KeyNotFoundException) {
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NullOnContainerNotFound implements FutureFallback<Object> {
|
||||
public static final class NullOnContainerNotFound implements Fallback<Object> {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) {
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof ContainerNotFoundException) {
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NullOnKeyNotFound implements FutureFallback<Object> {
|
||||
public static final class NullOnKeyNotFound implements Fallback<Object> {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) {
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof KeyNotFoundException) {
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ import static com.google.common.util.concurrent.Futures.immediateFuture;
|
|||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class TerremarkVCloudFallbacks {
|
||||
|
@ -40,19 +40,24 @@ public final class TerremarkVCloudFallbacks {
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public static final class VoidOnDeleteDefaultIp implements FutureFallback<Void> {
|
||||
public static final class VoidOnDeleteDefaultIp implements Fallback<Void> {
|
||||
public static final Pattern MESSAGE_PATTERN = Pattern
|
||||
.compile(".*Cannot release this Public IP as it is default oubound IP.*");
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> create(final Throwable t) {
|
||||
public ListenableFuture<Void> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof HttpResponseException) {
|
||||
HttpResponseException hre = HttpResponseException.class.cast(t);
|
||||
if (hre.getResponse().getStatusCode() == 503 || hre.getResponse().getStatusCode() == 401
|
||||
|| MESSAGE_PATTERN.matcher(hre.getMessage()).matches())
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
} else if (t instanceof AuthorizationException) {
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
throw propagate(t);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package org.jclouds.trmk.vcloud_0_8.internal;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NAME;
|
||||
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_NS;
|
||||
import static org.jclouds.trmk.vcloud_0_8.reference.TerremarkConstants.PROPERTY_TERREMARK_EXTENSION_VERSION;
|
||||
|
@ -32,9 +30,6 @@ public abstract class TerremarkVCloudApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "TerremarkVCloudLoginClient.login", SECONDS.toMillis(10) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "TerremarkVCloudVersionsClient.getSupportedVersions", SECONDS.toMillis(10) + "");
|
||||
properties.setProperty(PROPERTY_VCLOUD_VERSION_SCHEMA, "0.8");
|
||||
properties.setProperty(PROPERTY_SESSION_INTERVAL, 8 * 60 + "");
|
||||
properties.setProperty(PROPERTY_VCLOUD_XML_SCHEMA, "http://vcloud.safesecureweb.com/ns/vcloud.xsd");
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
|
||||
/**
|
||||
* Provides a backup value to replace an earlier exception.
|
||||
*
|
||||
* @param <V>
|
||||
* the result type of the backup value
|
||||
*
|
||||
* @author Adrian Cole
|
||||
* @see FutureFallback
|
||||
* @since 1.6
|
||||
*/
|
||||
@Beta
|
||||
public interface Fallback<V> extends FutureFallback<V> {
|
||||
/**
|
||||
* The exception is provided so that the {@code Fallback} implementation can
|
||||
* conditionally determine whether to propagate the exception or to attempt
|
||||
* to recover.
|
||||
*
|
||||
* @param t
|
||||
* the exception that made the call fail.
|
||||
*/
|
||||
V createOrPropagate(Throwable t) throws Exception;
|
||||
}
|
|
@ -40,7 +40,6 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -51,123 +50,153 @@ public final class Fallbacks {
|
|||
private Fallbacks() {
|
||||
}
|
||||
|
||||
public static final class NullOnNotFoundOr404 implements FutureFallback<Object> {
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) {
|
||||
return valOnNotFoundOr404(null, checkNotNull(t, "throwable"));
|
||||
public static final class NullOnNotFoundOr404 implements Fallback<Object> {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class VoidOnNotFoundOr404 implements FutureFallback<Void> {
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Void> create(Throwable t) {
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(null, checkNotNull(t, "throwable"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class TrueOnNotFoundOr404 implements FutureFallback<Boolean> {
|
||||
public static final class VoidOnNotFoundOr404 implements Fallback<Void> {
|
||||
public ListenableFuture<Void> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public Void createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(null, checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TrueOnNotFoundOr404 implements Fallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(true, checkNotNull(t, "throwable"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class FalseOnNotFoundOr404 implements FutureFallback<Boolean> {
|
||||
public static final class FalseOnNotFoundOr404 implements Fallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(false, checkNotNull(t, "throwable"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final class FalseOnNotFoundOr422 implements FutureFallback<Boolean> {
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
if (containsResourceNotFoundException(checkNotNull(t, "throwable"))
|
||||
|| returnValueOnCodeOrNull(t, true, equalTo(422)) != null)
|
||||
return immediateFuture(false);
|
||||
throw propagate(t);
|
||||
public static final class FalseOnNotFoundOr422 implements Fallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (containsResourceNotFoundException(checkNotNull(t, "throwable"))
|
||||
|| returnValueOnCodeOrNull(t, true, equalTo(422)) != null)
|
||||
return false;
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Leander Beernaert
|
||||
*/
|
||||
public static final class AbsentOn403Or404Or500 implements FutureFallback<Optional<Object>> {
|
||||
@Override
|
||||
public ListenableFuture<Optional<Object>> create(Throwable t) {
|
||||
Boolean returnVal = returnValueOnCodeOrNull(checkNotNull(t, "throwable"), true, in(asList(403, 404, 500)));
|
||||
if (returnVal != null)
|
||||
return immediateFuture(Optional.absent());
|
||||
throw propagate(t);
|
||||
|
||||
public static final class AbsentOn403Or404Or500 implements Fallback<Optional<Object>> {
|
||||
public ListenableFuture<Optional<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public Optional<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
Boolean returnVal = returnValueOnCodeOrNull(checkNotNull(t, "throwable"), true, in(asList(403, 404, 500)));
|
||||
if (returnVal != null)
|
||||
return Optional.absent();
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyFluentIterableOnNotFoundOr404 implements FutureFallback<FluentIterable<Object>> {
|
||||
@Override
|
||||
public ListenableFuture<FluentIterable<Object>> create(Throwable t) {
|
||||
public static final class EmptyFluentIterableOnNotFoundOr404 implements Fallback<FluentIterable<Object>> {
|
||||
public ListenableFuture<FluentIterable<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public FluentIterable<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(FluentIterable.from(ImmutableSet.of()), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyIterableWithMarkerOnNotFoundOr404 implements
|
||||
FutureFallback<IterableWithMarker<Object>> {
|
||||
@Override
|
||||
public ListenableFuture<IterableWithMarker<Object>> create(Throwable t) {
|
||||
public static final class EmptyIterableWithMarkerOnNotFoundOr404 implements Fallback<IterableWithMarker<Object>> {
|
||||
public ListenableFuture<IterableWithMarker<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public IterableWithMarker<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(IterableWithMarkers.from(ImmutableSet.of()), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyPagedIterableOnNotFoundOr404 implements FutureFallback<PagedIterable<Object>> {
|
||||
@Override
|
||||
public ListenableFuture<PagedIterable<Object>> create(Throwable t) {
|
||||
public static final class EmptyPagedIterableOnNotFoundOr404 implements Fallback<PagedIterable<Object>> {
|
||||
public ListenableFuture<PagedIterable<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public PagedIterable<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(PagedIterables.of(IterableWithMarkers.from(ImmutableSet.of())),
|
||||
checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyListOnNotFoundOr404 implements FutureFallback<ImmutableList<Object>> { // NO_UCD (unused code)
|
||||
@Override
|
||||
public ListenableFuture<ImmutableList<Object>> create(Throwable t) {
|
||||
public static final class EmptyListOnNotFoundOr404 implements Fallback<ImmutableList<Object>> { // NO_UCD
|
||||
// (unused
|
||||
// code)
|
||||
public ListenableFuture<ImmutableList<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public ImmutableList<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(ImmutableList.of(), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptySetOnNotFoundOr404 implements FutureFallback<ImmutableSet<Object>> {
|
||||
@Override
|
||||
public ListenableFuture<ImmutableSet<Object>> create(Throwable t) {
|
||||
public static final class EmptySetOnNotFoundOr404 implements Fallback<ImmutableSet<Object>> {
|
||||
public ListenableFuture<ImmutableSet<Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public ImmutableSet<Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(ImmutableSet.of(), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyMapOnNotFoundOr404 implements FutureFallback<ImmutableMap<Object, Object>> {
|
||||
@Override
|
||||
public ListenableFuture<ImmutableMap<Object, Object>> create(Throwable t) {
|
||||
public static final class EmptyMapOnNotFoundOr404 implements Fallback<ImmutableMap<Object, Object>> {
|
||||
public ListenableFuture<ImmutableMap<Object, Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public ImmutableMap<Object, Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(ImmutableMap.of(), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyMultimapOnNotFoundOr404 implements FutureFallback<ImmutableMultimap<Object, Object>> { // NO_UCD (unused code)
|
||||
@Override
|
||||
public ListenableFuture<ImmutableMultimap<Object, Object>> create(Throwable t) {
|
||||
public static final class EmptyMultimapOnNotFoundOr404 implements Fallback<ImmutableMultimap<Object, Object>> { // NO_UCD
|
||||
// (unused
|
||||
// code)
|
||||
public ListenableFuture<ImmutableMultimap<Object, Object>> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
public ImmutableMultimap<Object, Object> createOrPropagate(Throwable t) throws Exception {
|
||||
return valOnNotFoundOr404(ImmutableMultimap.of(), checkNotNull(t, "throwable"));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> ListenableFuture<T> valOnNotFoundOr404(T val, Throwable t) {
|
||||
public static <T> T valOnNotFoundOr404(T val, Throwable t) {
|
||||
if (containsResourceNotFoundException(checkNotNull(t, "throwable")) || contains404(t))
|
||||
return immediateFuture(val);
|
||||
return val;
|
||||
throw propagate(t);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,9 @@ import org.jclouds.lifecycle.Closer;
|
|||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.SimpleTimeLimiter;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.common.util.concurrent.TimeLimiter;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
|
@ -98,6 +100,12 @@ public class ExecutorServiceModule extends AbstractModule {
|
|||
protected void configure() { // NO_UCD
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
TimeLimiter timeLimiter(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor){
|
||||
return new SimpleTimeLimiter(userExecutor);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named(PROPERTY_USER_THREADS)
|
||||
|
|
|
@ -20,15 +20,16 @@ package org.jclouds.fallbacks;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -36,7 +37,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public final class MapHttp4xxCodesToExceptions implements FutureFallback<Object> {
|
||||
public final class MapHttp4xxCodesToExceptions implements Fallback<Object> {
|
||||
|
||||
private final PropagateIfRetryAfter propagateIfRetryAfter;
|
||||
|
||||
|
@ -46,7 +47,12 @@ public final class MapHttp4xxCodesToExceptions implements FutureFallback<Object>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Object> create(Throwable t) { // NO_UCD
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception { // NO_UCD
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
propagateIfRetryAfter.create(t); // if we pass here, we aren't a retry-after exception
|
||||
if (t instanceof HttpResponseException) {
|
||||
HttpResponseException responseException = HttpResponseException.class.cast(t);
|
||||
|
|
|
@ -27,15 +27,21 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface HttpCommandExecutorService {
|
||||
public interface HttpCommandExecutorService {
|
||||
|
||||
/**
|
||||
* Asks the command to build a request relevant for an endpoint that produces responses of
|
||||
* generic type {@code HttpResponse}. and invokes it on the endpoint, returning a future
|
||||
* Returns a potentially deferred {@code HttpResponse} from a server responding to the
|
||||
* {@code command}. The output {@code ListenableFuture} need not be
|
||||
* {@linkplain Future#isDone done}, making {@code HttpCommandExecutorService}
|
||||
* suitable for asynchronous derivations.
|
||||
*
|
||||
* @param command
|
||||
* that generates requests
|
||||
* @return {@link Future} containing the response from the {@code endpoint}
|
||||
*/
|
||||
ListenableFuture<HttpResponse> submit(HttpCommand command);
|
||||
|
||||
/**
|
||||
* Returns a {@code HttpResponse} from the server which responded to the
|
||||
* {@code command}.
|
||||
*/
|
||||
HttpResponse invoke(HttpCommand command);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
package org.jclouds.http.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.io.ByteStreams.copy;
|
||||
import static com.google.common.io.ByteStreams.nullOutputStream;
|
||||
import static org.jclouds.http.HttpUtils.checkRequestHasContentLengthOrChunkedEncoding;
|
||||
import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
||||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -46,7 +48,6 @@ import org.jclouds.http.handlers.DelegatingErrorHandler;
|
|||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.io.ContentMetadataCodec;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
|
@ -58,11 +59,11 @@ import com.google.common.util.concurrent.ListeningExecutorService;
|
|||
public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandExecutorService {
|
||||
protected final HttpUtils utils;
|
||||
protected final ContentMetadataCodec contentMetadataCodec;
|
||||
|
||||
private final DelegatingRetryHandler retryHandler;
|
||||
private final IOExceptionRetryHandler ioRetryHandler;
|
||||
private final DelegatingErrorHandler errorHandler;
|
||||
private final ListeningExecutorService ioExecutor;
|
||||
|
||||
protected final DelegatingRetryHandler retryHandler;
|
||||
protected final IOExceptionRetryHandler ioRetryHandler;
|
||||
protected final DelegatingErrorHandler errorHandler;
|
||||
protected final ListeningExecutorService ioExecutor;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
@ -74,9 +75,9 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
|
||||
@Inject
|
||||
protected BaseHttpCommandExecutorService(HttpUtils utils, ContentMetadataCodec contentMetadataCodec,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor,
|
||||
DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler,
|
||||
DelegatingErrorHandler errorHandler, HttpWire wire) {
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor,
|
||||
DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler,
|
||||
DelegatingErrorHandler errorHandler, HttpWire wire) {
|
||||
this.utils = checkNotNull(utils, "utils");
|
||||
this.contentMetadataCodec = checkNotNull(contentMetadataCodec, "contentMetadataCodec");
|
||||
this.retryHandler = checkNotNull(retryHandler, "retryHandler");
|
||||
|
@ -123,12 +124,71 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
HttpResponse response = null;
|
||||
for (;;) {
|
||||
HttpRequest request = command.getCurrentRequest();
|
||||
Q nativeRequest = null;
|
||||
try {
|
||||
for (HttpRequestFilter filter : request.getFilters()) {
|
||||
request = filter.filter(request);
|
||||
}
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After filtering, the request has neither chunked encoding nor content length: " + request);
|
||||
logger.debug("Sending request %s: %s", request.hashCode(), request.getRequestLine());
|
||||
wirePayloadIfEnabled(wire, request);
|
||||
utils.logRequest(headerLog, request, ">>");
|
||||
nativeRequest = convert(request);
|
||||
response = invoke(nativeRequest);
|
||||
|
||||
logger.debug("Receiving response %s: %s", request.hashCode(), response.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
nativeRequest = null; // response took ownership of streams
|
||||
int statusCode = response.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (shouldContinue(command, response))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
IOException ioe = getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
continue;
|
||||
}
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
||||
break;
|
||||
|
||||
} finally {
|
||||
cleanup(nativeRequest);
|
||||
}
|
||||
}
|
||||
if (command.getException() != null)
|
||||
throw propagate(command.getException());
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpCommand command, HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
errorHandler.handleError(command, response);
|
||||
}
|
||||
return shouldContinue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
HttpRequest request = command.getCurrentRequest();
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"if the request has a payload, it must be set to chunked encoding or specify a content length: "
|
||||
+ request);
|
||||
"if the request has a payload, it must be set to chunked encoding or specify a content length: " + request);
|
||||
return ioExecutor.submit(new HttpResponseCallable(command));
|
||||
}
|
||||
|
||||
|
@ -140,63 +200,12 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
|||
}
|
||||
|
||||
public HttpResponse call() throws Exception {
|
||||
|
||||
HttpResponse response = null;
|
||||
for (;;) {
|
||||
HttpRequest request = command.getCurrentRequest();
|
||||
Q nativeRequest = null;
|
||||
try {
|
||||
for (HttpRequestFilter filter : request.getFilters()) {
|
||||
request = filter.filter(request);
|
||||
}
|
||||
checkRequestHasContentLengthOrChunkedEncoding(request,
|
||||
"After filtering, the request has neither chunked encoding nor content length: " + request);
|
||||
logger.debug("Sending request %s: %s", request.hashCode(), request.getRequestLine());
|
||||
wirePayloadIfEnabled(wire, request);
|
||||
utils.logRequest(headerLog, request, ">>");
|
||||
nativeRequest = convert(request);
|
||||
response = invoke(nativeRequest);
|
||||
|
||||
logger.debug("Receiving response %s: %s", request.hashCode(), response.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
nativeRequest = null; // response took ownership of streams
|
||||
int statusCode = response.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (shouldContinue(response))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
continue;
|
||||
}
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
||||
break;
|
||||
|
||||
} finally {
|
||||
cleanup(nativeRequest);
|
||||
}
|
||||
try {
|
||||
return invoke(command);
|
||||
} finally {
|
||||
if (command.getException() != null)
|
||||
throw command.getException();
|
||||
}
|
||||
if (command.getException() != null)
|
||||
throw command.getException();
|
||||
return response;
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
errorHandler.handleError(command, response);
|
||||
}
|
||||
return shouldContinue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.jclouds.rest;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Collections2.filter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -29,7 +28,6 @@ import org.jclouds.predicates.Validator;
|
|||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.annotations.ParamValidators;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.reflect.Parameter;
|
||||
|
|
|
@ -24,10 +24,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
|
||||
/**
|
||||
* Annotates the appropriate {@link FutureFallback} which propagates the exception or returns a valid fallback value.
|
||||
* Annotates the appropriate {@link org.jclouds.Fallback} which propagates
|
||||
* the exception or returns a valid fallback value.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Adrian Cole
|
||||
|
@ -35,5 +34,5 @@ import com.google.common.util.concurrent.FutureFallback;
|
|||
@Target(METHOD)
|
||||
@Retention(RUNTIME)
|
||||
public @interface Fallback {
|
||||
Class<? extends FutureFallback<?>> value();
|
||||
Class<? extends org.jclouds.Fallback<?>> value();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 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 current 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.rest.config;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.util.concurrent.UncheckedTimeoutException;
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
/**
|
||||
* Provides the ability to decouple timeouts and fallbacks from what's built-in.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Beta
|
||||
@ImplementedBy(ReadAnnotationsAndProperties.class)
|
||||
public interface InvocationConfig {
|
||||
|
||||
/**
|
||||
* If this is present, Sync method calls will block up to the specified nanos
|
||||
* and throw an {@linkplain UncheckedTimeoutException}. If this is not
|
||||
* present, Sync method calls will be invoked directly, typically through
|
||||
* {@linkplain HttpCommandExecutorService#invoke}.
|
||||
*/
|
||||
Optional<Long> getTimeoutNanos(Invocation in);
|
||||
|
||||
/**
|
||||
* command named used in logging and configuration keys.
|
||||
*/
|
||||
String getCommandName(Invocation invocation);
|
||||
|
||||
/**
|
||||
* fallback used for Sync or Async commands.
|
||||
*/
|
||||
Fallback<?> getFallback(Invocation invocation);
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* 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 current 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.rest.config;
|
||||
|
||||
import static com.google.common.base.Optional.fromNullable;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.util.Maps2.transformKeys;
|
||||
import static org.jclouds.util.Predicates2.startsWith;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.annotations.Fallback;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
@Beta
|
||||
@Singleton
|
||||
public class ReadAnnotationsAndProperties implements InvocationConfig {
|
||||
private final Injector injector;
|
||||
private final org.jclouds.Fallback<Object> defaultFallback;
|
||||
private final Map<String, Long> timeouts;
|
||||
|
||||
@Inject
|
||||
ReadAnnotationsAndProperties(Injector injector,
|
||||
Function<Predicate<String>, Map<String, String>> filterStringsBoundByName,
|
||||
org.jclouds.Fallback<Object> defaultFallback) {
|
||||
this.injector = injector;
|
||||
this.defaultFallback = defaultFallback;
|
||||
this.timeouts = timeouts(filterStringsBoundByName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Long> getTimeoutNanos(Invocation in) {
|
||||
String commandName = getCommandName(in);
|
||||
Optional<Long> defaultMillis = fromNullable(timeouts.get("default"));
|
||||
Optional<Long> timeoutMillis = fromNullable(timeouts.get(commandName));
|
||||
Invokable<?, ?> invoked = in.getInvokable();
|
||||
if (invoked.isAnnotationPresent(Named.class)) {
|
||||
timeoutMillis = timeoutMillis.or(defaultMillis);
|
||||
} else {
|
||||
// TODO: remove old logic once Named annotations are on all methods
|
||||
String className = invoked.getOwnerType().getRawType().getSimpleName().replace("AsyncClient", "Client")
|
||||
.replace("AsyncApi", "Api");
|
||||
timeoutMillis = timeoutMillis.or(fromNullable(timeouts.get(className))).or(defaultMillis);
|
||||
}
|
||||
if (timeoutMillis.isPresent())
|
||||
return Optional.of(MILLISECONDS.toNanos(timeoutMillis.get()));
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName(Invocation invocation) {
|
||||
Invokable<?, ?> invoked = invocation.getInvokable();
|
||||
if (invoked.isAnnotationPresent(Named.class)) {
|
||||
return invoked.getAnnotation(Named.class).value();
|
||||
} else {
|
||||
// TODO: remove old logic once Named annotations are on all methods
|
||||
String className = invoked.getOwnerType().getRawType().getSimpleName().replace("AsyncClient", "Client")
|
||||
.replace("AsyncApi", "Api");
|
||||
return className + "." + invoked.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.jclouds.Fallback<?> getFallback(Invocation invocation) {
|
||||
Fallback fallback = invocation.getInvokable().getAnnotation(Fallback.class);
|
||||
if (fallback != null) {
|
||||
return injector.getInstance(fallback.value());
|
||||
}
|
||||
return defaultFallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* override timeout by values configured in properties(in ms)
|
||||
*/
|
||||
static Map<String, Long> timeouts(Function<Predicate<String>, Map<String, String>> filterStringsBoundByName) {
|
||||
Map<String, String> stringBoundWithTimeoutPrefix = filterStringsBoundByName
|
||||
.apply(startsWith(PROPERTY_TIMEOUTS_PREFIX));
|
||||
Map<String, Long> longsByName = transformValues(stringBoundWithTimeoutPrefix, new Function<String, Long>() {
|
||||
public Long apply(String input) {
|
||||
return Long.valueOf(String.valueOf(input));
|
||||
}
|
||||
});
|
||||
return transformKeys(longsByName, new Function<String, String>() {
|
||||
public String apply(String input) {
|
||||
return input.replaceFirst(PROPERTY_TIMEOUTS_PREFIX, "");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -22,34 +22,34 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Iterables.toArray;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static com.google.common.util.concurrent.Atomics.newReference;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.method;
|
||||
import static org.jclouds.reflect.Reflection2.methods;
|
||||
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
|
||||
import static org.jclouds.util.Maps2.transformKeys;
|
||||
import static org.jclouds.util.Predicates2.startsWith;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.functions.IdentityFunction;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.config.SaxParserModule;
|
||||
import org.jclouds.internal.FilterStringsBoundToInjectorByName;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.location.config.LocationModule;
|
||||
import org.jclouds.proxy.ProxyForURI;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.jclouds.rest.HttpAsyncClient;
|
||||
import org.jclouds.rest.HttpClient;
|
||||
import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith;
|
||||
import org.jclouds.rest.internal.BlockOnFuture;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.rest.internal.TransformerForRequest;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
|
@ -90,6 +90,21 @@ public class RestModule extends AbstractModule {
|
|||
return seedKnownSync2AsyncInvokables(sync2Async);
|
||||
}
|
||||
|
||||
/**
|
||||
* function view of above
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
protected Function<Invocation, Invocation> sync2async(final Cache<Invokable<?, ?>, Invokable<?, ?>> cache) {
|
||||
return new Function<Invocation, Invocation>() {
|
||||
public Invocation apply(Invocation in) {
|
||||
return Invocation.create(
|
||||
checkNotNull(cache.getIfPresent(in.getInvokable()), "invokable %s not in %s", in.getInvokable(),
|
||||
cache), in.getArgs());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Cache<Invokable<?, ?>, Invokable<?, ?>> seedKnownSync2AsyncInvokables(Map<Class<?>, Class<?>> sync2Async) {
|
||||
Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncBuilder = CacheBuilder.newBuilder().build();
|
||||
|
@ -133,7 +148,12 @@ public class RestModule extends AbstractModule {
|
|||
install(new GsonModule());
|
||||
install(new SetCaller.Module());
|
||||
install(new FactoryModuleBuilder().build(BindToJsonPayloadWrappedWith.Factory.class));
|
||||
install(new FactoryModuleBuilder().build(BlockOnFuture.Factory.class));
|
||||
bind(new TypeLiteral<Function<HttpRequest, Function<HttpResponse, ?>>>() {
|
||||
}).to(TransformerForRequest.class);
|
||||
bind(new TypeLiteral<org.jclouds.Fallback<Object>>() {
|
||||
}).to(MapHttp4xxCodesToExceptions.class);
|
||||
bind(new TypeLiteral<Function<Invocation, HttpRequest>>() {
|
||||
}).to(RestAnnotationProcessor.class);
|
||||
bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE);
|
||||
bindHttpApi(binder(), HttpClient.class, HttpAsyncClient.class);
|
||||
// this will help short circuit scenarios that can otherwise lock out users
|
||||
|
@ -145,23 +165,4 @@ public class RestModule extends AbstractModule {
|
|||
}).to(ProxyForURI.class);
|
||||
installLocations();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("TIMEOUTS")
|
||||
protected Map<String, Long> timeouts(Function<Predicate<String>, Map<String, String>> filterStringsBoundByName) {
|
||||
Map<String, String> stringBoundWithTimeoutPrefix = filterStringsBoundByName
|
||||
.apply(startsWith(PROPERTY_TIMEOUTS_PREFIX));
|
||||
Map<String, Long> longsByName = transformValues(stringBoundWithTimeoutPrefix, new Function<String, Long>() {
|
||||
public Long apply(String input) {
|
||||
return Long.valueOf(String.valueOf(input));
|
||||
}
|
||||
});
|
||||
return transformKeys(longsByName, new Function<String, String>() {
|
||||
public String apply(String input) {
|
||||
return input.replaceFirst(PROPERTY_TIMEOUTS_PREFIX, "");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,132 +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.rest.internal;
|
||||
|
||||
import static com.google.common.base.Optional.fromNullable;
|
||||
import static com.google.common.collect.ObjectArrays.concat;
|
||||
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.common.util.concurrent.UncheckedTimeoutException;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
public class BlockOnFuture implements Function<ListenableFuture<?>, Object> {
|
||||
|
||||
public static interface Factory {
|
||||
/**
|
||||
* @param invocation
|
||||
* context for how the future was created
|
||||
*/
|
||||
BlockOnFuture create(Invocation invocation);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
|
||||
private final Map<String, Long> timeouts;
|
||||
private final Invocation invocation;
|
||||
|
||||
@Inject
|
||||
@VisibleForTesting
|
||||
BlockOnFuture(@Named("TIMEOUTS") Map<String, Long> timeouts, @Assisted Invocation invocation) {
|
||||
this.timeouts = timeouts;
|
||||
this.invocation = invocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(ListenableFuture<?> future) {
|
||||
Optional<Long> timeoutNanos = timeoutInNanos(invocation.getInvokable(), timeouts);
|
||||
return block(future, timeoutNanos);
|
||||
}
|
||||
|
||||
private Object block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
|
||||
try {
|
||||
if (timeoutNanos.isPresent()) {
|
||||
logger.debug(">> blocking on %s for %s", future, timeoutNanos);
|
||||
return getUninterruptibly(future, timeoutNanos.get(), NANOSECONDS);
|
||||
} else {
|
||||
logger.debug(">> blocking on %s", future);
|
||||
return getUninterruptibly(future);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
throw propagateCause(e);
|
||||
} catch (TimeoutException e) {
|
||||
future.cancel(true);
|
||||
throw new UncheckedTimeoutException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static RuntimeException propagateCause(Exception e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause == null) {
|
||||
UncheckedExecutionException unchecked = new UncheckedExecutionException(e.getMessage()) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
};
|
||||
unchecked.setStackTrace(e.getStackTrace());
|
||||
throw unchecked;
|
||||
}
|
||||
StackTraceElement[] combined = concat(cause.getStackTrace(), e.getStackTrace(), StackTraceElement.class);
|
||||
cause.setStackTrace(combined);
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
}
|
||||
if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
}
|
||||
// The cause is a weird kind of Throwable, so throw the outer exception.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// override timeout by values configured in properties(in ms)
|
||||
private Optional<Long> timeoutInNanos(Invokable<?, ?> invoked, Map<String, Long> timeouts) {
|
||||
Optional<Long> defaultMillis = fromNullable(timeouts.get("default"));
|
||||
Optional<Long> timeoutMillis;
|
||||
if (invoked.isAnnotationPresent(Named.class)) {
|
||||
String commandName = invoked.getAnnotation(Named.class).value();
|
||||
timeoutMillis = fromNullable(timeouts.get(commandName)).or(defaultMillis);
|
||||
} else {
|
||||
// TODO: remove old logic, once Named annotations are present on all methods
|
||||
String className = invoked.getOwnerType().getRawType().getSimpleName().replace("AsyncClient", "Client")
|
||||
.replace("AsyncApi", "Api");
|
||||
timeoutMillis = fromNullable(timeouts.get(className + "." + invoked.getName())).or(
|
||||
fromNullable(timeouts.get(className))).or(defaultMillis);
|
||||
}
|
||||
if (timeoutMillis.isPresent())
|
||||
return Optional.of(TimeUnit.MILLISECONDS.toNanos(timeoutMillis.get()));
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.rest.internal;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.getUnchecked;
|
||||
|
||||
|
@ -32,7 +31,6 @@ import org.jclouds.reflect.Invocation;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
|
@ -45,7 +43,7 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
|
|||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
|
||||
private final Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncInvokables;
|
||||
private final Function<Invocation, Invocation> sync2async;
|
||||
private final R receiver;
|
||||
|
||||
/**
|
||||
|
@ -55,8 +53,8 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
|
|||
*/
|
||||
@Inject
|
||||
@VisibleForTesting
|
||||
InvokeAndCallGetOnFutures(Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncInvokables, R receiver) {
|
||||
this.sync2AsyncInvokables = sync2AsyncInvokables;
|
||||
InvokeAndCallGetOnFutures(Function<Invocation, Invocation> sync2async, R receiver) {
|
||||
this.sync2async = sync2async;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
|
@ -64,8 +62,7 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
|
|||
@Override
|
||||
public Object apply(Invocation in) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Invokable target = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",
|
||||
in.getInvokable(), sync2AsyncInvokables);
|
||||
Invokable target = sync2async.apply(in).getInvokable();
|
||||
Object returnVal;
|
||||
try {
|
||||
returnVal = target.invoke(receiver, in.getArgs().toArray());
|
||||
|
|
|
@ -19,114 +19,240 @@
|
|||
package org.jclouds.rest.internal;
|
||||
|
||||
import static com.google.common.base.Objects.equal;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Objects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.transform;
|
||||
import static com.google.common.util.concurrent.Futures.withFallback;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_USER_THREADS;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.InvocationContext;
|
||||
import org.jclouds.rest.annotations.Fallback;
|
||||
import org.jclouds.rest.config.InvocationConfig;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.common.util.concurrent.TimeLimiter;
|
||||
import com.google.common.util.concurrent.UncheckedTimeoutException;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class InvokeHttpMethod implements Function<Invocation, Object> {
|
||||
|
||||
@Resource
|
||||
private Logger logger = Logger.NULL;
|
||||
|
||||
private final Injector injector;
|
||||
private final Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncInvokables;
|
||||
private final RestAnnotationProcessor annotationProcessor;
|
||||
private final Function<Invocation, Invocation> sync2async;
|
||||
private final Function<Invocation, HttpRequest> annotationProcessor;
|
||||
private final HttpCommandExecutorService http;
|
||||
private final TransformerForRequest transformerForRequest;
|
||||
private final ListeningExecutorService userExecutor;
|
||||
private final BlockOnFuture.Factory blocker;
|
||||
private final TimeLimiter timeLimiter;
|
||||
private final Function<HttpRequest, Function<HttpResponse, ?>> transformerForRequest;
|
||||
private final InvocationConfig config;
|
||||
|
||||
@Inject
|
||||
private InvokeHttpMethod(Injector injector, Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncInvokables,
|
||||
RestAnnotationProcessor annotationProcessor, HttpCommandExecutorService http,
|
||||
TransformerForRequest transformerForRequest,
|
||||
@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, BlockOnFuture.Factory blocker) {
|
||||
this.injector = injector;
|
||||
this.sync2AsyncInvokables = sync2AsyncInvokables;
|
||||
@VisibleForTesting
|
||||
InvokeHttpMethod(Function<Invocation, Invocation> sync2async, Function<Invocation, HttpRequest> annotationProcessor,
|
||||
HttpCommandExecutorService http, Function<HttpRequest, Function<HttpResponse, ?>> transformerForRequest,
|
||||
TimeLimiter timeLimiter, InvocationConfig config,
|
||||
@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor) {
|
||||
this.sync2async = sync2async;
|
||||
this.annotationProcessor = annotationProcessor;
|
||||
this.http = http;
|
||||
this.userExecutor = userExecutor;
|
||||
this.blocker = blocker;
|
||||
this.timeLimiter = timeLimiter;
|
||||
this.transformerForRequest = transformerForRequest;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private final LoadingCache<Invokable<?, ?>, FutureFallback<?>> fallbacks = CacheBuilder.newBuilder().build(
|
||||
new CacheLoader<Invokable<?, ?>, FutureFallback<?>>() {
|
||||
|
||||
@Override
|
||||
public FutureFallback<?> load(Invokable<?, ?> key) throws Exception {
|
||||
Fallback annotation = key.getAnnotation(Fallback.class);
|
||||
if (annotation != null) {
|
||||
return injector.getInstance(annotation.value());
|
||||
}
|
||||
return injector.getInstance(MapHttp4xxCodesToExceptions.class);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@Override
|
||||
public Object apply(Invocation in) {
|
||||
if (isFuture(in.getInvokable())) {
|
||||
return createFuture(in);
|
||||
return submit(in);
|
||||
}
|
||||
Invocation async = Invocation.create(
|
||||
checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",
|
||||
in.getInvokable(), sync2AsyncInvokables), in.getArgs());
|
||||
Invocation async = toAsync(in);
|
||||
Optional<Long> timeoutNanos = config.getTimeoutNanos(async);
|
||||
if (timeoutNanos.isPresent()) {
|
||||
return invokeWithTimeout(async, timeoutNanos.get());
|
||||
}
|
||||
return invoke(async);
|
||||
}
|
||||
|
||||
/**
|
||||
* submits the {@linkplain HttpCommand} associated with {@code invocation},
|
||||
* {@link #getTransformer(String, HttpCommand) parses its response}, and
|
||||
* applies a {@link #getFallback(String, Invocation, HttpCommand) fallback}
|
||||
* if a {@code Throwable} is encountered. Parsing and Fallback occur on the
|
||||
* {@code userExecutor} thread.
|
||||
*/
|
||||
public ListenableFuture<?> submit(Invocation invocation) {
|
||||
String commandName = config.getCommandName(invocation);
|
||||
HttpCommand command = toCommand(commandName, invocation);
|
||||
Function<HttpResponse, ?> transformer = getTransformer(commandName, command);
|
||||
org.jclouds.Fallback<?> fallback = getFallback(commandName, invocation, command);
|
||||
|
||||
logger.debug(">> submitting %s", commandName);
|
||||
return withFallback(transform(http.submit(command), transformer, userExecutor), fallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* invokes the {@linkplain HttpCommand} associated with {@code invocation},
|
||||
* {@link #getTransformer(String, HttpCommand) parses its response}, and
|
||||
* applies a {@link #getFallback(String, Invocation, HttpCommand) fallback}
|
||||
* if a {@code Throwable} is encountered.
|
||||
*/
|
||||
public Object invoke(Invocation invocation) {
|
||||
String commandName = config.getCommandName(invocation);
|
||||
HttpCommand command = toCommand(commandName, invocation);
|
||||
Function<HttpResponse, ?> transformer = getTransformer(commandName, command);
|
||||
org.jclouds.Fallback<?> fallback = getFallback(commandName, invocation, command);
|
||||
|
||||
logger.debug(">> invoking %s", commandName);
|
||||
try {
|
||||
return transformer.apply(http.invoke(command));
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
return fallback.createOrPropagate(t);
|
||||
} catch (Exception e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calls {@link #invoke(Invocation)}, timing out after the specified time
|
||||
* limit. If the target method call finished before the limit is reached, the
|
||||
* return value or exception is propagated to the caller exactly as-is. If,
|
||||
* on the other hand, the time limit is reached, we attempt to abort the call
|
||||
* to the target, and throw an {@link UncheckedTimeoutException} to the
|
||||
* caller.
|
||||
*
|
||||
* @param invocation
|
||||
* the Invocation to invoke via {@link #invoke(Invocation)}
|
||||
* @param limitNanos
|
||||
* with timeoutUnit, the maximum length of time to wait in
|
||||
* nanoseconds
|
||||
* @throws InterruptedException
|
||||
* if our thread is interrupted during execution
|
||||
* @throws UncheckedTimeoutException
|
||||
* if the time limit is reached
|
||||
* @see TimeLimiter#callWithTimeout(Callable, long, TimeUnit, boolean)
|
||||
*/
|
||||
public Object invokeWithTimeout(final Invocation invocation, final long limitNanos) {
|
||||
String commandName = config.getCommandName(invocation);
|
||||
HttpCommand command = toCommand(commandName, invocation);
|
||||
org.jclouds.Fallback<?> fallback = getFallback(commandName, invocation, command);
|
||||
|
||||
logger.debug(">> blocking on %s for %s", invocation, limitNanos);
|
||||
try {
|
||||
return timeLimiter
|
||||
.callWithTimeout(new InvokeAndTransform(commandName, command), limitNanos, NANOSECONDS, true);
|
||||
} catch (Throwable t) {
|
||||
try {
|
||||
return fallback.createOrPropagate(t);
|
||||
} catch (Exception e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private org.jclouds.Fallback<?> getFallback(String commandName, Invocation invocation, HttpCommand command) {
|
||||
HttpRequest request = command.getCurrentRequest();
|
||||
org.jclouds.Fallback<?> fallback = config.getFallback(invocation);
|
||||
if (fallback instanceof InvocationContext)
|
||||
InvocationContext.class.cast(fallback).setContext(request);
|
||||
logger.trace("<< exceptions from %s are parsed by %s", commandName, fallback.getClass().getSimpleName());
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final class InvokeAndTransform implements Callable<Object> {
|
||||
private final String commandName;
|
||||
private final HttpCommand command;
|
||||
private final Function<HttpResponse, ?> transformer;
|
||||
|
||||
InvokeAndTransform(String commandName, HttpCommand command) {
|
||||
this.commandName = commandName;
|
||||
this.command = command;
|
||||
this.transformer = getTransformer(commandName, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception {
|
||||
return transformer.apply(http.invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(commandName, command, transformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
InvokeAndTransform that = InvokeAndTransform.class.cast(obj);
|
||||
return equal(this.commandName, that.commandName) && equal(this.command, that.command)
|
||||
&& equal(this.transformer, that.transformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringHelper(this).add("commandName", commandName).add("command", command)
|
||||
.add("transformer", transformer).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* looks up the corresponding {@code Invocation} that returns a
|
||||
* {@code Future}. Only Invokables that return {@code Futures} are annotated
|
||||
* in a way that can be parsed into an {@linkplain HttpRequest}.
|
||||
*/
|
||||
private Invocation toAsync(Invocation in) {
|
||||
Invocation async = sync2async.apply(in);
|
||||
checkState(isFuture(async.getInvokable()), "not a future: %s", async);
|
||||
return blocker.create(async).apply(createFuture(async));
|
||||
return async;
|
||||
}
|
||||
|
||||
private HttpCommand toCommand(String commandName, Invocation invocation) {
|
||||
logger.trace(">> converting %s", commandName);
|
||||
HttpRequest request = annotationProcessor.apply(invocation);
|
||||
logger.trace("<< converted %s to %s", commandName, request.getRequestLine());
|
||||
return new HttpCommand(request);
|
||||
}
|
||||
|
||||
private Function<HttpResponse, ?> getTransformer(String commandName, HttpCommand command) {
|
||||
HttpRequest request = command.getCurrentRequest();
|
||||
Function<HttpResponse, ?> transformer = transformerForRequest.apply(request);
|
||||
logger.trace("<< response from %s is parsed by %s", commandName, transformer.getClass().getSimpleName());
|
||||
return transformer;
|
||||
}
|
||||
|
||||
private boolean isFuture(Invokable<?, ?> in) {
|
||||
return in.getReturnType().getRawType().equals(ListenableFuture.class);
|
||||
}
|
||||
|
||||
public ListenableFuture<?> createFuture(Invocation invocation) {
|
||||
String name = invocation.getInvokable().toString();
|
||||
logger.trace(">> converting %s", name);
|
||||
GeneratedHttpRequest request = annotationProcessor.apply(invocation);
|
||||
logger.trace("<< converted %s to %s", name, request.getRequestLine());
|
||||
|
||||
Function<HttpResponse, ?> transformer = transformerForRequest.apply(request);
|
||||
logger.trace("<< response from %s is parsed by %s", name, transformer.getClass().getSimpleName());
|
||||
|
||||
logger.debug(">> invoking %s", name);
|
||||
ListenableFuture<?> result = transform(http.submit(new HttpCommand(request)), transformer, userExecutor);
|
||||
|
||||
FutureFallback<?> fallback = fallbacks.getUnchecked(invocation.getInvokable());
|
||||
if (fallback instanceof InvocationContext) {
|
||||
InvocationContext.class.cast(fallback).setContext(request);
|
||||
}
|
||||
logger.trace("<< exceptions from %s are parsed by %s", name, fallback.getClass().getSimpleName());
|
||||
return withFallback(result, fallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
|
|
|
@ -131,7 +131,7 @@ import com.google.inject.TypeLiteral;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RestAnnotationProcessor implements Function<Invocation, GeneratedHttpRequest> {
|
||||
public class RestAnnotationProcessor implements Function<Invocation, HttpRequest> {
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
|
|
@ -35,6 +35,7 @@ import javax.lang.model.type.NullType;
|
|||
|
||||
import org.jclouds.functions.IdentityFunction;
|
||||
import org.jclouds.functions.OnlyElementOrNull;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
|
||||
import org.jclouds.http.functions.ParseJson;
|
||||
|
@ -69,7 +70,7 @@ import com.google.inject.Injector;
|
|||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
public class TransformerForRequest implements Function<GeneratedHttpRequest, Function<HttpResponse, ?>> {
|
||||
public class TransformerForRequest implements Function<HttpRequest, Function<HttpResponse, ?>> {
|
||||
private final ParseSax.Factory parserFactory;
|
||||
private final Injector injector;
|
||||
private final GetAcceptHeaders getAcceptHeaders;
|
||||
|
@ -83,7 +84,8 @@ public class TransformerForRequest implements Function<GeneratedHttpRequest, Fun
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Function<HttpResponse, ?> apply(GeneratedHttpRequest request) {
|
||||
public Function<HttpResponse, ?> apply(HttpRequest in) {
|
||||
GeneratedHttpRequest request = GeneratedHttpRequest.class.cast(in);
|
||||
Function<HttpResponse, ?> transformer;
|
||||
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(request.getInvocation()
|
||||
.getInvokable());
|
||||
|
@ -93,7 +95,7 @@ public class TransformerForRequest implements Function<GeneratedHttpRequest, Fun
|
|||
transformer = getTransformerForMethod(request.getInvocation(), injector);
|
||||
}
|
||||
if (transformer instanceof InvocationContext<?>) {
|
||||
((InvocationContext<?>) transformer).setContext(request);
|
||||
InvocationContext.class.cast(transformer).setContext(request);
|
||||
}
|
||||
if (request.getInvocation().getInvokable().isAnnotationPresent(Transform.class)) {
|
||||
Function<?, ?> wrappingTransformer = injector.getInstance(request.getInvocation().getInvokable()
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/**
|
||||
* 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 current 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.fallbacks;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
|
|
|
@ -36,27 +36,27 @@ import com.google.common.net.HttpHeaders;
|
|||
public class MapHttp4xxCodesToExceptionsTest {
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void test401ToAuthorizationException() {
|
||||
public void test401ToAuthorizationException() throws Exception {
|
||||
fn.create(new HttpResponseException(command, HttpResponse.builder().statusCode(401).build()));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AuthorizationException.class)
|
||||
public void test403ToAuthorizationException() {
|
||||
public void test403ToAuthorizationException() throws Exception {
|
||||
fn.create(new HttpResponseException(command, HttpResponse.builder().statusCode(403).build()));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ResourceNotFoundException.class)
|
||||
public void test404ToResourceNotFoundException() {
|
||||
public void test404ToResourceNotFoundException() throws Exception {
|
||||
fn.create(new HttpResponseException(command, HttpResponse.builder().statusCode(404).build()));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void test409ToIllegalStateException() {
|
||||
public void test409ToIllegalStateException() throws Exception {
|
||||
fn.create(new HttpResponseException(command, HttpResponse.builder().statusCode(409).build()));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RetryAfterException.class, expectedExceptionsMessageRegExp = "retry now")
|
||||
public void testHttpResponseExceptionWithRetryAfterDate() {
|
||||
public void testHttpResponseExceptionWithRetryAfterDate() throws Exception {
|
||||
fn.create(new HttpResponseException(command,
|
||||
HttpResponse.builder()
|
||||
.statusCode(503)
|
||||
|
@ -64,7 +64,7 @@ public class MapHttp4xxCodesToExceptionsTest {
|
|||
}
|
||||
|
||||
@Test(expectedExceptions = RetryAfterException.class, expectedExceptionsMessageRegExp = "retry in 700 seconds")
|
||||
public void testHttpResponseExceptionWithRetryAfterOffset(){
|
||||
public void testHttpResponseExceptionWithRetryAfterOffset() throws Exception {
|
||||
fn.create(new HttpResponseException(command,
|
||||
HttpResponse.builder()
|
||||
.statusCode(503)
|
||||
|
@ -72,7 +72,7 @@ public class MapHttp4xxCodesToExceptionsTest {
|
|||
}
|
||||
|
||||
@Test(expectedExceptions = RetryAfterException.class, expectedExceptionsMessageRegExp = "retry in 86400 seconds")
|
||||
public void testHttpResponseExceptionWithRetryAfterPastIsZero(){
|
||||
public void testHttpResponseExceptionWithRetryAfterPastIsZero() throws Exception {
|
||||
fn.create(new HttpResponseException(command,
|
||||
HttpResponse.builder()
|
||||
.statusCode(503)
|
||||
|
|
|
@ -52,7 +52,6 @@ import org.jclouds.util.Strings2;
|
|||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
|
@ -92,13 +91,14 @@ public interface IntegrationTestAsyncClient {
|
|||
@Fallback(FooOnException.class)
|
||||
ListenableFuture<String> downloadException(@PathParam("id") String id, HttpRequestOptions options);
|
||||
|
||||
static class FooOnException implements FutureFallback<String> {
|
||||
|
||||
@Override
|
||||
static class FooOnException implements org.jclouds.Fallback<String> {
|
||||
public ListenableFuture<String> create(Throwable t) throws Exception {
|
||||
return immediateFuture("foo");
|
||||
}
|
||||
|
||||
public String createOrPropagate(Throwable t) throws Exception {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Properties;
|
|||
|
||||
import org.jclouds.http.BaseJettyTest;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.IntegrationTestAsyncClient;
|
||||
import org.jclouds.io.Payloads;
|
||||
|
@ -34,6 +35,7 @@ import org.jclouds.reflect.Invocation;
|
|||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
|
@ -122,7 +124,7 @@ public class BackoffLimitedRetryHandlerTest {
|
|||
assertEquals(response.getPayload().getInput().read(), -1);
|
||||
}
|
||||
|
||||
private final RestAnnotationProcessor processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector()
|
||||
private final Function<Invocation, HttpRequest> processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector()
|
||||
.getInstance(RestAnnotationProcessor.class);
|
||||
|
||||
private HttpCommand createCommand() throws SecurityException, NoSuchMethodException {
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.ws.rs.POST;
|
|||
import javax.ws.rs.PathParam;
|
||||
|
||||
import org.jclouds.ContextBuilder;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.IntegrationTestAsyncClient;
|
||||
import org.jclouds.http.IntegrationTestClient;
|
||||
import org.jclouds.predicates.validators.AllLowerCaseValidator;
|
||||
|
@ -35,6 +36,7 @@ import org.testng.TestException;
|
|||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.inject.Injector;
|
||||
|
@ -105,7 +107,7 @@ public class InputParamValidatorTest {
|
|||
}
|
||||
|
||||
Injector injector;
|
||||
RestAnnotationProcessor restAnnotationProcessor;
|
||||
Function<Invocation, HttpRequest> restAnnotationProcessor;
|
||||
|
||||
@BeforeClass
|
||||
void setupFactory() {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* 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 current 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.rest.config;
|
||||
|
||||
import static org.jclouds.reflect.Reflection2.method;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
|
||||
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.internal.FilterStringsBoundToInjectorByName;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.annotations.Fallback;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true)
|
||||
public class ReadAnnotationsAndPropertiesTest {
|
||||
|
||||
public static interface ThingApi {
|
||||
HttpResponse get();
|
||||
|
||||
HttpResponse namedGet();
|
||||
}
|
||||
|
||||
public static interface ThingAsyncApi {
|
||||
ListenableFuture<HttpResponse> get();
|
||||
|
||||
@Named("ns:get")
|
||||
@Fallback(FalseOnNotFoundOr404.class)
|
||||
ListenableFuture<HttpResponse> namedGet();
|
||||
}
|
||||
|
||||
private Invocation asyncGet;
|
||||
private Invocation asyncNamedGet;
|
||||
private org.jclouds.Fallback<Object> defaultFallback;
|
||||
|
||||
@BeforeClass
|
||||
void setupInvocations() throws SecurityException, NoSuchMethodException {
|
||||
asyncGet = Invocation.create(method(ThingAsyncApi.class, "get"), ImmutableList.of());
|
||||
asyncNamedGet = Invocation.create(method(ThingAsyncApi.class, "namedGet"), ImmutableList.of());
|
||||
defaultFallback = new NullOnNotFoundOr404();
|
||||
}
|
||||
|
||||
/**
|
||||
* this functionality will be removed once Named annotations are on all async
|
||||
* classes.
|
||||
*/
|
||||
public void testInvocationsSetDefaultTimeoutOnAsyncMethods() throws Exception {
|
||||
final Properties props = new Properties();
|
||||
props.setProperty("jclouds.timeouts.default", "250");
|
||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||
protected void configure() {
|
||||
Names.bindProperties(binder(), props);
|
||||
}
|
||||
});
|
||||
ReadAnnotationsAndProperties config = new ReadAnnotationsAndProperties(injector,
|
||||
new FilterStringsBoundToInjectorByName(injector), defaultFallback);
|
||||
assertEquals(config.getTimeoutNanos(asyncGet), Optional.of(250000000l));
|
||||
assertEquals(config.getTimeoutNanos(asyncNamedGet), Optional.of(250000000l));
|
||||
}
|
||||
|
||||
public void testNamedInvocationGetsTimeoutOverrideOnAsyncMethods() throws Exception {
|
||||
final Properties props = new Properties();
|
||||
props.setProperty("jclouds.timeouts.default", "50");
|
||||
props.setProperty("jclouds.timeouts.ThingApi", "100");
|
||||
props.setProperty("jclouds.timeouts.ns:get", "250");
|
||||
Injector injector = Guice.createInjector(new AbstractModule() {
|
||||
protected void configure() {
|
||||
Names.bindProperties(binder(), props);
|
||||
}
|
||||
});
|
||||
ReadAnnotationsAndProperties config = new ReadAnnotationsAndProperties(injector,
|
||||
new FilterStringsBoundToInjectorByName(injector), defaultFallback);
|
||||
assertEquals(config.getTimeoutNanos(asyncNamedGet), Optional.of(250000000l));
|
||||
}
|
||||
|
||||
/**
|
||||
* this functionality will be removed once Named annotations are on all async
|
||||
* classes.
|
||||
*/
|
||||
public void testNamingConventionOfUnnamedMethods() throws Exception {
|
||||
Injector injector = Guice.createInjector();
|
||||
ReadAnnotationsAndProperties config = new ReadAnnotationsAndProperties(injector,
|
||||
new FilterStringsBoundToInjectorByName(injector), defaultFallback);
|
||||
assertEquals(config.getCommandName(asyncGet), "ThingApi.get");
|
||||
}
|
||||
|
||||
public void testNamingConventionOfNamedAsyncMethods() throws Exception {
|
||||
Injector injector = Guice.createInjector();
|
||||
ReadAnnotationsAndProperties config = new ReadAnnotationsAndProperties(injector,
|
||||
new FilterStringsBoundToInjectorByName(injector), defaultFallback);
|
||||
assertEquals(config.getCommandName(asyncNamedGet), "ns:get");
|
||||
}
|
||||
|
||||
public void testFallbackOverride() throws Exception {
|
||||
Injector injector = Guice.createInjector();
|
||||
ReadAnnotationsAndProperties config = new ReadAnnotationsAndProperties(injector,
|
||||
new FilterStringsBoundToInjectorByName(injector), defaultFallback);
|
||||
assertEquals(config.getFallback(asyncNamedGet).getClass(), FalseOnNotFoundOr404.class);
|
||||
assertEquals(config.getFallback(asyncGet), defaultFallback);
|
||||
}
|
||||
}
|
|
@ -84,12 +84,15 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.InputSupplier;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.SimpleTimeLimiter;
|
||||
import com.google.common.util.concurrent.TimeLimiter;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
|
@ -236,6 +239,12 @@ public abstract class BaseRestApiExpectTest<S> {
|
|||
}).toInstance(fn);
|
||||
bind(HttpCommandExecutorService.class).to(ExpectHttpCommandExecutorService.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
TimeLimiter timeLimiter(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor){
|
||||
return new SimpleTimeLimiter(userExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,6 +33,9 @@ import java.io.IOException;
|
|||
import java.util.Date;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.concurrent.config.ConfiguresExecutorService;
|
||||
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
|
@ -51,8 +54,11 @@ import com.google.common.collect.SortedSetMultimap;
|
|||
import com.google.common.collect.TreeMultimap;
|
||||
import com.google.common.reflect.Invokable;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.SimpleTimeLimiter;
|
||||
import com.google.common.util.concurrent.TimeLimiter;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -83,6 +89,12 @@ public abstract class BaseRestApiTest {
|
|||
bind(ListeningExecutorService.class).annotatedWith(named(PROPERTY_IO_WORKER_THREADS)).toInstance(sameThreadExecutor());
|
||||
bind(HttpCommandExecutorService.class).toInstance(mock);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
TimeLimiter timeLimiter(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor){
|
||||
return new SimpleTimeLimiter(userExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertPayloadEquals(HttpRequest request, String toMatch, String contentType, boolean contentMD5) {
|
||||
|
|
|
@ -1,138 +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.rest.internal;
|
||||
|
||||
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.jclouds.reflect.Reflection2.method;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true)
|
||||
public class BlockOnFutureTest {
|
||||
|
||||
static ListenableFuture<String> future;
|
||||
|
||||
public static class ThingAsyncApi {
|
||||
public ListenableFuture<String> get() {
|
||||
return future;
|
||||
}
|
||||
|
||||
@Named("ns:get")
|
||||
public ListenableFuture<String> namedGet() {
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
||||
private Invocation get;
|
||||
private Invocation namedGet;
|
||||
|
||||
@BeforeClass
|
||||
void setupInvocations() throws SecurityException, NoSuchMethodException {
|
||||
get = Invocation.create(method(ThingAsyncApi.class, "get"), ImmutableList.of());
|
||||
namedGet = Invocation.create(method(ThingAsyncApi.class, "namedGet"), ImmutableList.of());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeMethod
|
||||
void createMockedFuture() throws InterruptedException, ExecutionException, TimeoutException {
|
||||
future = createMock(ListenableFuture.class);
|
||||
expect(future.get(250000000, TimeUnit.NANOSECONDS)).andReturn("foo");
|
||||
replay(future);
|
||||
}
|
||||
|
||||
public void testUnnamedMethodWithDefaultPropTimeout() throws Exception {
|
||||
Function<ListenableFuture<?>, Object> withOverride = new BlockOnFuture(ImmutableMap.of("default", 250L), get);
|
||||
assertEquals(withOverride.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
public void testUnnamedMethodWithClassPropTimeout() throws Exception {
|
||||
Function<ListenableFuture<?>, Object> withOverride = new BlockOnFuture(ImmutableMap.of("default", 50L,
|
||||
"ThingApi", 250L), get);
|
||||
assertEquals(withOverride.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
public void testUnnamedMethodWithMethodPropTimeout() throws Exception {
|
||||
Function<ListenableFuture<?>, Object> withOverride = new BlockOnFuture(ImmutableMap.of("default", 50L,
|
||||
"ThingApi", 100L, "ThingApi.get", 250L), get);
|
||||
assertEquals(withOverride.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testUnnamedMethodWithNoTimeoutsCallGetDirectly() throws Exception {
|
||||
future = createMock(ListenableFuture.class);
|
||||
expect(future.get()).andReturn("foo");
|
||||
replay(future);
|
||||
|
||||
Function<ListenableFuture<?>, Object> noOverrides = new BlockOnFuture(ImmutableMap.<String, Long> of(), get);
|
||||
|
||||
assertEquals(noOverrides.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
public void testNamedMethodWithDefaultPropTimeout() throws Exception {
|
||||
Function<ListenableFuture<?>, Object> withOverride = new BlockOnFuture(ImmutableMap.of("default", 250L), namedGet);
|
||||
assertEquals(withOverride.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
public void testNamedMethodWithMethodPropTimeout() throws Exception {
|
||||
Function<ListenableFuture<?>, Object> withOverride = new BlockOnFuture(ImmutableMap.of("default", 50L,
|
||||
"ThingApi", 100L, "ns:get", 250L), namedGet);
|
||||
assertEquals(withOverride.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testNamedMethodWithNoTimeoutsCallGetDirectly() throws Exception {
|
||||
future = createMock(ListenableFuture.class);
|
||||
expect(future.get()).andReturn("foo");
|
||||
replay(future);
|
||||
|
||||
Function<ListenableFuture<?>, Object> noOverrides = new BlockOnFuture(ImmutableMap.<String, Long> of(), namedGet);
|
||||
|
||||
assertEquals(noOverrides.apply(future), "foo");
|
||||
verify(future);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/**
|
||||
* 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.rest.internal;
|
||||
|
||||
import static org.easymock.EasyMock.anyObject;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.eq;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.jclouds.reflect.Reflection2.method;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.config.InvocationConfig;
|
||||
import org.jclouds.rest.internal.InvokeHttpMethod.InvokeAndTransform;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.common.util.concurrent.TimeLimiter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", singleThreaded = true)
|
||||
public class InvokeHttpMethodTest {
|
||||
|
||||
public static interface ThingApi {
|
||||
HttpResponse get();
|
||||
}
|
||||
|
||||
public static interface ThingAsyncApi {
|
||||
@Named("ns:get")
|
||||
ListenableFuture<HttpResponse> get();
|
||||
}
|
||||
|
||||
private Invocation get;
|
||||
private Invocation asyncGet;
|
||||
private Function<Invocation, Invocation> sync2async;
|
||||
private HttpRequest getRequest = HttpRequest.builder().method("GET").endpoint("http://get").build();
|
||||
private HttpCommand getCommand = new HttpCommand(getRequest);
|
||||
private Function<Invocation, HttpRequest> toRequest;
|
||||
|
||||
@BeforeClass
|
||||
void setupInvocations() throws SecurityException, NoSuchMethodException {
|
||||
get = Invocation.create(method(ThingApi.class, "get"), ImmutableList.of());
|
||||
asyncGet = Invocation.create(method(ThingAsyncApi.class, "get"), ImmutableList.of());
|
||||
sync2async = Functions.forMap(ImmutableMap.of(get, asyncGet));
|
||||
toRequest = Functions.forMap(ImmutableMap.of(asyncGet, getRequest));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Function<HttpRequest, Function<HttpResponse, ?>> transformerForRequest = Function.class.cast(Functions
|
||||
.constant(Functions.identity()));
|
||||
private ListeningExecutorService userThreads = MoreExecutors.sameThreadExecutor();
|
||||
|
||||
private HttpResponse response = HttpResponse.builder().statusCode(200).payload("foo").build();
|
||||
private HttpCommandExecutorService http;
|
||||
private TimeLimiter timeLimiter;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private org.jclouds.Fallback fallback;
|
||||
private InvocationConfig config;
|
||||
private InvokeHttpMethod invokeHttpMethod;
|
||||
|
||||
private ListenableFuture<HttpResponse> future;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeMethod
|
||||
void createMocks() {
|
||||
http = createMock(HttpCommandExecutorService.class);
|
||||
timeLimiter = createMock(TimeLimiter.class);
|
||||
fallback = createMock(org.jclouds.Fallback.class);
|
||||
config = createMock(InvocationConfig.class);
|
||||
future = createMock(ListenableFuture.class);
|
||||
invokeHttpMethod = new InvokeHttpMethod(sync2async, toRequest, http, transformerForRequest, timeLimiter, config,
|
||||
userThreads);
|
||||
expect(config.getCommandName(asyncGet)).andReturn("ns:get");
|
||||
expect(config.getFallback(asyncGet)).andReturn(fallback);
|
||||
}
|
||||
|
||||
@AfterMethod
|
||||
void verifyMocks() {
|
||||
verify(http, timeLimiter, fallback, config, future);
|
||||
}
|
||||
|
||||
public void testMethodWithTimeoutRunsTimeLimiter() throws Exception {
|
||||
expect(config.getTimeoutNanos(asyncGet)).andReturn(Optional.of(250000000l));
|
||||
InvokeAndTransform invoke = invokeHttpMethod.new InvokeAndTransform("ns:get", getCommand);
|
||||
expect(timeLimiter.callWithTimeout(invoke, 250000000, TimeUnit.NANOSECONDS, true)).andReturn(response);
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
invokeHttpMethod.apply(get);
|
||||
}
|
||||
|
||||
public void testMethodWithNoTimeoutCallGetDirectly() throws Exception {
|
||||
expect(config.getTimeoutNanos(asyncGet)).andReturn(Optional.<Long> absent());
|
||||
expect(http.invoke(new HttpCommand(getRequest))).andReturn(response);
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
invokeHttpMethod.apply(get);
|
||||
}
|
||||
|
||||
public void testAsyncMethodSubmitsRequest() throws Exception {
|
||||
expect(http.submit(new HttpCommand(getRequest))).andReturn(future);
|
||||
future.addListener(anyObject(Runnable.class), eq(userThreads));
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
invokeHttpMethod.apply(asyncGet);
|
||||
}
|
||||
|
||||
private HttpResponse fallbackResponse = HttpResponse.builder().statusCode(200).payload("bar").build();
|
||||
|
||||
public void testDirectCallRunsFallbackCreateOrPropagate() throws Exception {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
expect(config.getTimeoutNanos(asyncGet)).andReturn(Optional.<Long> absent());
|
||||
expect(http.invoke(new HttpCommand(getRequest))).andThrow(exception);
|
||||
expect(fallback.createOrPropagate(exception)).andReturn(fallbackResponse);
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
assertEquals(invokeHttpMethod.apply(get), fallbackResponse);
|
||||
}
|
||||
|
||||
public void testTimeLimitedRunsFallbackCreateOrPropagate() throws Exception {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
expect(config.getTimeoutNanos(asyncGet)).andReturn(Optional.of(250000000l));
|
||||
InvokeAndTransform invoke = invokeHttpMethod.new InvokeAndTransform("ns:get", getCommand);
|
||||
expect(timeLimiter.callWithTimeout(invoke, 250000000, TimeUnit.NANOSECONDS, true)).andThrow(exception);
|
||||
expect(fallback.createOrPropagate(exception)).andReturn(fallbackResponse);
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
assertEquals(invokeHttpMethod.apply(get), fallbackResponse);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSubmitRunsFallbackCreateOnGet() throws Exception {
|
||||
IllegalStateException exception = new IllegalStateException();
|
||||
expect(http.submit(new HttpCommand(getRequest))).andReturn(
|
||||
Futures.<HttpResponse> immediateFailedFuture(exception));
|
||||
expect(fallback.create(exception)).andReturn(Futures.<HttpResponse> immediateFuture(fallbackResponse));
|
||||
// not using the field, as you can see above we are making an immediate
|
||||
// failed future instead.
|
||||
future = createMock(ListenableFuture.class);
|
||||
replay(http, timeLimiter, fallback, config, future);
|
||||
assertEquals(ListenableFuture.class.cast(invokeHttpMethod.apply(asyncGet)).get(), fallbackResponse);
|
||||
}
|
||||
}
|
|
@ -249,9 +249,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(),
|
||||
"GET http://localhost:9999/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -274,6 +279,11 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
if (callCounter == 1)
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(),
|
||||
"GET http://localhost:1111/client/1/bar/2 HTTP/1.1");
|
||||
|
@ -281,7 +291,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
assertEquals(command.getCurrentRequest().getRequestLine(),
|
||||
"GET http://localhost:1111/client/1/foo HTTP/1.1");
|
||||
callCounter++;
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -304,8 +314,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://howdyboys/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -329,9 +344,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(),
|
||||
"GET http://howdyboys/testing/testing/thepathparam/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -355,8 +375,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://howdyboys/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -380,8 +405,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://howdyboys/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
}, new AbstractModule() {
|
||||
|
@ -419,8 +449,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest {
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(HttpCommand command) {
|
||||
return Futures.immediateFuture(invoke(command));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse invoke(HttpCommand command) {
|
||||
assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://howdyboys/client/1/foo HTTP/1.1");
|
||||
return Futures.immediateFuture(HttpResponse.builder().build());
|
||||
return HttpResponse.builder().build();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
@ -26,12 +26,12 @@ import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.JcloudsVersion;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpCommandExecutorService;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
|
@ -42,58 +42,72 @@ import org.jclouds.http.HttpUtils;
|
|||
import org.jclouds.http.IOExceptionRetryHandler;
|
||||
import org.jclouds.http.handlers.DelegatingErrorHandler;
|
||||
import org.jclouds.http.handlers.DelegatingRetryHandler;
|
||||
import org.jclouds.http.internal.BaseHttpCommandExecutorService;
|
||||
import org.jclouds.http.internal.HttpWire;
|
||||
import org.jclouds.logging.Logger;
|
||||
import org.jclouds.io.ContentMetadataCodec;
|
||||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.appengine.api.urlfetch.HTTPRequest;
|
||||
import com.google.appengine.api.urlfetch.HTTPResponse;
|
||||
import com.google.appengine.api.urlfetch.URLFetchService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
|
||||
/**
|
||||
* Google App Engine version of {@link HttpCommandExecutorService} using their fetchAsync call
|
||||
* Google App Engine version of {@link HttpCommandExecutorService} using their
|
||||
* fetchAsync call
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class AsyncGaeHttpCommandExecutorService implements HttpCommandExecutorService {
|
||||
private final ListeningExecutorService ioExecutor;
|
||||
public class AsyncGaeHttpCommandExecutorService extends BaseHttpCommandExecutorService<HTTPRequest> {
|
||||
// TODO: look up gae version
|
||||
public static final String USER_AGENT = String.format("jclouds/%s urlfetch/%s", JcloudsVersion.get(), "1.6.5");
|
||||
|
||||
private final URLFetchService urlFetchService;
|
||||
private final ConvertToGaeRequest convertToGaeRequest;
|
||||
private final ConvertToJcloudsResponse convertToJcloudsResponse;
|
||||
private final DelegatingRetryHandler retryHandler;
|
||||
private final IOExceptionRetryHandler ioRetryHandler;
|
||||
private final DelegatingErrorHandler errorHandler;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
@Resource
|
||||
@Named(Constants.LOGGER_HTTP_HEADERS)
|
||||
protected Logger headerLog = Logger.NULL;
|
||||
protected final HttpWire wire;
|
||||
protected final HttpUtils utils;
|
||||
private final ListeningExecutorService ioExecutor;
|
||||
|
||||
@Inject
|
||||
public AsyncGaeHttpCommandExecutorService(
|
||||
public AsyncGaeHttpCommandExecutorService(URLFetchService urlFetchService, HttpUtils utils,
|
||||
ContentMetadataCodec contentMetadataCodec,
|
||||
@Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor,
|
||||
URLFetchService urlFetchService, ConvertToGaeRequest convertToGaeRequest,
|
||||
ConvertToJcloudsResponse convertToJcloudsResponse, DelegatingRetryHandler retryHandler,
|
||||
IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpUtils utils, HttpWire wire) {
|
||||
IOExceptionRetryHandler ioRetryHandler, DelegatingRetryHandler retryHandler,
|
||||
DelegatingErrorHandler errorHandler, HttpWire wire, ConvertToGaeRequest convertToGaeRequest,
|
||||
ConvertToJcloudsResponse convertToJcloudsResponse) {
|
||||
super(utils, contentMetadataCodec, ioExecutor, retryHandler, ioRetryHandler, errorHandler, wire);
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.urlFetchService = urlFetchService;
|
||||
this.convertToGaeRequest = convertToGaeRequest;
|
||||
this.convertToJcloudsResponse = convertToJcloudsResponse;
|
||||
this.retryHandler = retryHandler;
|
||||
this.ioRetryHandler = ioRetryHandler;
|
||||
this.errorHandler = errorHandler;
|
||||
this.utils = utils;
|
||||
this.wire = wire;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected HttpResponse convert(HTTPResponse gaeResponse) {
|
||||
return convertToJcloudsResponse.apply(gaeResponse);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected HTTPRequest convert(HttpRequest request) throws IOException {
|
||||
return convertToGaeRequest.apply(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* nothing to clean up.
|
||||
*/
|
||||
@Override
|
||||
protected void cleanup(HTTPRequest nativeRequest) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpResponse invoke(HTTPRequest request) throws IOException {
|
||||
return convert(urlFetchService.fetch(request));
|
||||
}
|
||||
|
||||
public HTTPRequest filterLogAndConvertRe(HttpRequest request) {
|
||||
|
||||
for (HttpRequestFilter filter : request.getFilters()) {
|
||||
request = filter.filter(request);
|
||||
}
|
||||
|
@ -108,61 +122,59 @@ public class AsyncGaeHttpCommandExecutorService implements HttpCommandExecutorSe
|
|||
|
||||
@Override
|
||||
public ListenableFuture<HttpResponse> submit(final HttpCommand command) {
|
||||
|
||||
HTTPRequest nativeRequest = filterLogAndConvertRe(command.getCurrentRequest());
|
||||
|
||||
ListenableFuture<HttpResponse> response = transform(
|
||||
listenInPoolThread(urlFetchService.fetchAsync(nativeRequest)), convertToJcloudsResponse);
|
||||
|
||||
return transform(response, new Function<HttpResponse, HttpResponse>() {
|
||||
|
||||
@Override
|
||||
public HttpResponse apply(HttpResponse response) {
|
||||
try {
|
||||
logger.debug("Receiving response %s: %s", command.getCurrentRequest().hashCode(),
|
||||
response.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
int statusCode = response.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (shouldContinue(response))
|
||||
return submit(command).get();
|
||||
else
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
try {
|
||||
return submit(command).get();
|
||||
} catch (Exception e1) {
|
||||
command.setException(e1);
|
||||
return response;
|
||||
}
|
||||
} else {
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
||||
return response;
|
||||
}
|
||||
} finally {
|
||||
if (command.getException() != null)
|
||||
propagate(command.getException());
|
||||
}
|
||||
return receiveResponse(command, response);
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
errorHandler.handleError(command, response);
|
||||
}
|
||||
return shouldContinue;
|
||||
}
|
||||
}, ioExecutor);
|
||||
|
||||
}
|
||||
|
||||
private HttpResponse receiveResponse(HttpCommand command, HttpResponse response) {
|
||||
try {
|
||||
logger.debug("Receiving response %s: %s", command.getCurrentRequest().hashCode(), response.getStatusLine());
|
||||
utils.logResponse(headerLog, response, "<<");
|
||||
if (response.getPayload() != null && wire.enabled())
|
||||
wire.input(response);
|
||||
int statusCode = response.getStatusCode();
|
||||
if (statusCode >= 300) {
|
||||
if (shouldContinue(command, response))
|
||||
return submit(command).get();
|
||||
else
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
IOException ioe = Throwables2.getFirstThrowableOfType(e, IOException.class);
|
||||
if (ioe != null && ioRetryHandler.shouldRetryRequest(command, ioe)) {
|
||||
try {
|
||||
return submit(command).get();
|
||||
} catch (Exception e1) {
|
||||
command.setException(e1);
|
||||
return response;
|
||||
}
|
||||
} else {
|
||||
command.setException(new HttpResponseException(e.getMessage() + " connecting to "
|
||||
+ command.getCurrentRequest().getRequestLine(), command, null, e));
|
||||
return response;
|
||||
}
|
||||
} finally {
|
||||
if (command.getException() != null)
|
||||
propagate(command.getException());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldContinue(HttpCommand command, HttpResponse response) {
|
||||
boolean shouldContinue = false;
|
||||
if (retryHandler.shouldRetryRequest(command, response)) {
|
||||
shouldContinue = true;
|
||||
} else {
|
||||
errorHandler.handleError(command, response);
|
||||
}
|
||||
return shouldContinue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
|
|||
@Singleton
|
||||
public class GaeHttpCommandExecutorService extends BaseHttpCommandExecutorService<HTTPRequest> {
|
||||
//TODO: look up gae version
|
||||
public static final String USER_AGENT = String.format("jclouds/%s urlfetch/%s", JcloudsVersion.get(), "1.4.3");
|
||||
public static final String USER_AGENT = String.format("jclouds/%s urlfetch/%s", JcloudsVersion.get(), "1.6.5");
|
||||
|
||||
private final URLFetchService urlFetchService;
|
||||
private final ConvertToGaeRequest convertToGaeRequest;
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
*/
|
||||
|
||||
package org.jclouds.abiquo;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_MAX_REDIRECTS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
|
||||
import static org.jclouds.abiquo.config.AbiquoProperties.CREDENTIAL_IS_TOKEN;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
@ -67,7 +65,6 @@ public class AbiquoApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
|
||||
// By default redirects will be handled in the domain objects
|
||||
properties.setProperty(PROPERTY_MAX_REDIRECTS, "0");
|
||||
// The default polling delay between AsyncTask monitor requests
|
||||
|
|
|
@ -26,13 +26,13 @@ import static com.google.common.util.concurrent.Futures.immediateFuture;
|
|||
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.abiquo.domain.exception.AbiquoException;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -47,22 +47,30 @@ public final class AbiquoFallbacks {
|
|||
/**
|
||||
* Return an Abiquo Exception on not found errors.
|
||||
*/
|
||||
public static final class PropagateAbiquoExceptionOnNotFoundOr4xx implements FutureFallback<Object> {
|
||||
public static final class PropagateAbiquoExceptionOnNotFoundOr4xx implements Fallback<Object> {
|
||||
@Override
|
||||
public ListenableFuture<Object> create(final Throwable from) {
|
||||
Throwable exception = find(getCausalChain(from), isNotFoundAndHasAbiquoException(from), null);
|
||||
|
||||
throw propagate(exception == null ? from : exception.getCause());
|
||||
public ListenableFuture<Object> create(Throwable from) throws Exception {
|
||||
return immediateFuture(createOrPropagate(from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrPropagate(Throwable from) throws Exception {
|
||||
Throwable exception = find(getCausalChain(from), isNotFoundAndHasAbiquoException(from), null);
|
||||
throw propagate(exception == null ? from : exception.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>null</code> on 303 response codes when requesting a task.
|
||||
*/
|
||||
public static final class NullOn303 implements FutureFallback<Object> {
|
||||
public static final class NullOn303 implements Fallback<Object> {
|
||||
@Override
|
||||
public ListenableFuture<Object> create(final Throwable from) {
|
||||
public ListenableFuture<Object> create(Throwable from) throws Exception {
|
||||
return immediateFuture(createOrPropagate(from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrPropagate(Throwable from) throws Exception {
|
||||
Throwable exception = find(getCausalChain(from), hasResponse(from), null);
|
||||
|
||||
if (exception != null) {
|
||||
|
@ -70,7 +78,7 @@ public final class AbiquoFallbacks {
|
|||
HttpResponse response = responseException.getResponse();
|
||||
|
||||
if (response != null && response.getStatusCode() == Status.SEE_OTHER.getStatusCode()) {
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,9 +90,14 @@ public final class AbiquoFallbacks {
|
|||
/**
|
||||
* Return false on service error exceptions.
|
||||
*/
|
||||
public static final class FalseOn5xx implements FutureFallback<Boolean> {
|
||||
public static final class FalseOn5xx implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(final Throwable from) {
|
||||
public ListenableFuture<Boolean> create(Throwable from) throws Exception {
|
||||
return immediateFuture(createOrPropagate(from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable from) throws Exception {
|
||||
Throwable exception = find(getCausalChain(from), hasResponse(from), null);
|
||||
|
||||
if (exception != null) {
|
||||
|
@ -92,7 +105,7 @@ public final class AbiquoFallbacks {
|
|||
HttpResponse response = responseException.getResponse();
|
||||
|
||||
if (response != null && response.getStatusCode() >= 500 && response.getStatusCode() < 600) {
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,9 +117,14 @@ public final class AbiquoFallbacks {
|
|||
/**
|
||||
* Return false on service error exceptions.
|
||||
*/
|
||||
public static final class FalseIfNotAvailable implements FutureFallback<Boolean> {
|
||||
public static final class FalseIfNotAvailable implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(final Throwable from) {
|
||||
public ListenableFuture<Boolean> create(Throwable from) throws Exception {
|
||||
return immediateFuture(createOrPropagate(from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable from) throws Exception {
|
||||
Throwable exception = find(getCausalChain(from), isNotAvailableException(from), null);
|
||||
|
||||
if (exception != null) {
|
||||
|
@ -115,11 +133,11 @@ public final class AbiquoFallbacks {
|
|||
HttpResponse response = responseException.getResponse();
|
||||
|
||||
if (response != null && response.getStatusCode() >= 500 && response.getStatusCode() < 600) {
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Will enter here when exception is a ResourceNotFoundException
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.inject.Inject;
|
|||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.http.functions.ParseXMLWithJAXB;
|
||||
|
@ -37,7 +38,6 @@ import com.abiquo.server.core.infrastructure.storage.MovedVolumeDto;
|
|||
import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
|
@ -47,7 +47,7 @@ import com.google.inject.TypeLiteral;
|
|||
* @author Ignasi Barrera
|
||||
*/
|
||||
@Singleton
|
||||
public class MovedVolume implements FutureFallback<VolumeManagementDto> {
|
||||
public class MovedVolume implements Fallback<VolumeManagementDto> {
|
||||
|
||||
@Singleton
|
||||
@VisibleForTesting
|
||||
|
@ -67,14 +67,19 @@ public class MovedVolume implements FutureFallback<VolumeManagementDto> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<VolumeManagementDto> create(final Throwable from) {
|
||||
public ListenableFuture<VolumeManagementDto> create(Throwable from) throws Exception {
|
||||
return immediateFuture(createOrPropagate(from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolumeManagementDto createOrPropagate(Throwable from) throws Exception {
|
||||
Throwable exception = find(getCausalChain(from), isMovedException(from), null);
|
||||
|
||||
if (exception != null) {
|
||||
HttpResponseException responseException = (HttpResponseException) exception;
|
||||
HttpResponse response = responseException.getResponse();
|
||||
|
||||
return immediateFuture(parser.apply(response).getVolume());
|
||||
return parser.apply(response).getVolume();
|
||||
}
|
||||
|
||||
throw propagate(from);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.jclouds.abiquo.fallbacks;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.getUnchecked;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
@ -45,13 +44,13 @@ public class FalseIfNotAvailableTest {
|
|||
RuntimeException exception = new RuntimeException();
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFalseIf5xx() {
|
||||
public void testFalseIf5xx() throws Exception {
|
||||
FalseIfNotAvailable function = new FalseIfNotAvailable();
|
||||
HttpResponse response = EasyMock.createMock(HttpResponse.class);
|
||||
HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
|
||||
|
@ -68,7 +67,7 @@ public class FalseIfNotAvailableTest {
|
|||
replay(response);
|
||||
replay(exception);
|
||||
|
||||
assertFalse(getUnchecked(function.create(exception)));
|
||||
assertFalse(function.createOrPropagate(exception));
|
||||
|
||||
verify(response);
|
||||
verify(exception);
|
||||
|
@ -92,7 +91,7 @@ public class FalseIfNotAvailableTest {
|
|||
replay(exception);
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
|
@ -101,11 +100,11 @@ public class FalseIfNotAvailableTest {
|
|||
verify(exception);
|
||||
}
|
||||
|
||||
public void testFalseIfResourceNotFound() {
|
||||
public void testFalseIfResourceNotFound() throws Exception {
|
||||
FalseIfNotAvailable function = new FalseIfNotAvailable();
|
||||
ResourceNotFoundException exception = new ResourceNotFoundException();
|
||||
|
||||
assertFalse(getUnchecked(function.create(exception)));
|
||||
assertFalse(function.createOrPropagate(exception));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.jclouds.abiquo.fallbacks;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.getUnchecked;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
@ -44,13 +43,13 @@ public class FalseOn5xxTest {
|
|||
RuntimeException exception = new RuntimeException();
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFalseIf5xx() {
|
||||
public void testFalseIf5xx() throws Exception {
|
||||
FalseOn5xx function = new FalseOn5xx();
|
||||
HttpResponse response = EasyMock.createMock(HttpResponse.class);
|
||||
HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
|
||||
|
@ -67,7 +66,7 @@ public class FalseOn5xxTest {
|
|||
replay(response);
|
||||
replay(exception);
|
||||
|
||||
assertFalse(getUnchecked(function.create(exception)));
|
||||
assertFalse(function.createOrPropagate(exception));
|
||||
|
||||
verify(response);
|
||||
verify(exception);
|
||||
|
@ -91,7 +90,7 @@ public class FalseOn5xxTest {
|
|||
replay(exception);
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ import static org.easymock.EasyMock.replay;
|
|||
import static org.easymock.EasyMock.verify;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
|
@ -61,7 +59,7 @@ public class MovedVolumeTest {
|
|||
}
|
||||
}
|
||||
|
||||
public void testReturnVolume() throws IOException {
|
||||
public void testReturnVolume() throws Exception {
|
||||
JAXBParser xmlParser = new JAXBParser("false");
|
||||
MovedVolume function = new MovedVolume(new ReturnMoveVolumeReference(
|
||||
new JAXBParser("false"), TypeLiteral.get(MovedVolumeDto.class)));
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.jclouds.abiquo.fallbacks;
|
||||
|
||||
import static com.google.common.util.concurrent.Futures.getUnchecked;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
@ -44,13 +43,13 @@ public class NullOn303Test {
|
|||
RuntimeException exception = new RuntimeException();
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void testNullIf303() {
|
||||
public void testNullIf303() throws Exception {
|
||||
NullOn303 function = new NullOn303();
|
||||
HttpResponse response = EasyMock.createMock(HttpResponse.class);
|
||||
HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
|
||||
|
@ -66,7 +65,7 @@ public class NullOn303Test {
|
|||
replay(response);
|
||||
replay(exception);
|
||||
|
||||
assertNull(getUnchecked(function.create(exception)));
|
||||
assertNull(function.createOrPropagate(exception));
|
||||
|
||||
verify(response);
|
||||
verify(exception);
|
||||
|
@ -89,7 +88,7 @@ public class NullOn303Test {
|
|||
replay(exception);
|
||||
|
||||
try {
|
||||
function.create(exception);
|
||||
function.createOrPropagate(exception);
|
||||
} catch (Exception ex) {
|
||||
assertEquals(ex, exception);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.azure.management;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.azure.management.config.AzureManagementProperties.SUBSCRIPTION_ID;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
|
@ -66,7 +64,6 @@ public class AzureManagementApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.snia.cdmi.v1;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -59,8 +56,6 @@ public class CDMIApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "DataNonCDMIContentTypeApi", MINUTES.toMillis(10) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.cloudstack.ec2;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -57,7 +54,6 @@ public class CloudStackEC2ApiMetadata extends EC2ApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = EC2ApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ec2:DescribeImages", MINUTES.toMillis(15) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.dynect.v3;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -62,7 +59,6 @@ public class DynECTApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ import static com.google.common.base.Throwables.propagate;
|
|||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import org.jclouds.Fallback;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -34,10 +35,16 @@ public final class DynECTFallbacks {
|
|||
private DynECTFallbacks() {
|
||||
}
|
||||
|
||||
public static class FalseOn400 implements FutureFallback<Boolean> {
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public static class FalseOn400 implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (returnValueOnCodeOrNull(t, false, equalTo(400)) != null)
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
throw propagate(t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.elb;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
|
||||
|
@ -63,7 +61,6 @@ public class ELBApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.fujitsu.fgcp;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -57,7 +55,6 @@ public class FGCPApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
// enables peer verification using the CAs bundled with the JRE (or
|
||||
// value of javax.net.ssl.trustStore if set)
|
||||
properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
|
||||
|
|
|
@ -18,9 +18,13 @@
|
|||
*/
|
||||
package org.jclouds.googlecompute;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.googlecompute.config.GoogleComputeParserModule;
|
||||
import org.jclouds.googlecompute.config.GoogleComputeRestClientModule;
|
||||
|
@ -29,14 +33,9 @@ import org.jclouds.oauth.v2.config.OAuthAuthenticationModule;
|
|||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for GoogleCompute v1beta13 API
|
||||
|
@ -64,7 +63,6 @@ public class GoogleComputeApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.put("oauth.endpoint", "https://accounts.google.com/o/oauth2/token");
|
||||
properties.put(AUDIENCE, "https://accounts.google.com/o/oauth2/token");
|
||||
properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256");
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.iam;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
|
||||
|
@ -59,7 +57,6 @@ public class IAMApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.jenkins.v1;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -61,7 +58,6 @@ public class JenkinsApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,9 @@ import static com.google.common.base.Throwables.propagate;
|
|||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -36,13 +37,18 @@ public final class JenkinsFallbacks {
|
|||
private JenkinsFallbacks() {
|
||||
}
|
||||
|
||||
public static final class VoidOn302Or404 implements FutureFallback<Void> {
|
||||
public static final class VoidOn302Or404 implements Fallback<Void> {
|
||||
@Override
|
||||
public ListenableFuture<Void> create(final Throwable t) {
|
||||
public ListenableFuture<Void> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void createOrPropagate(Throwable t) throws Exception {
|
||||
Boolean returnVal = returnValueOnCodeOrNull(checkNotNull(t, "throwable"), true,
|
||||
Predicates.<Integer> or(equalTo(302), equalTo(404)));
|
||||
if (returnVal != null && returnVal)
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
throw propagate(t);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
package org.jclouds.joyent.cloudapi.v6_5;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -63,7 +61,6 @@ public class JoyentCloudApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
// auth fail sometimes happens, as the rc.local script that injects the
|
||||
// authorized key executes after ssh has started.
|
||||
properties.setProperty("jclouds.ssh.max-retries", "7");
|
||||
|
|
|
@ -18,22 +18,21 @@
|
|||
*/
|
||||
package org.jclouds.oauth.v2;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.oauth.v2.config.OAuthModule;
|
||||
import org.jclouds.oauth.v2.config.OAuthRestClientModule;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.oauth.v2.config.OAuthProperties.SIGNATURE_OR_MAC_ALGORITHM;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for OAuth 2 API
|
||||
|
@ -61,7 +60,6 @@ public class OAuthApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(1) + "");
|
||||
properties.put(SIGNATURE_OR_MAC_ALGORITHM, "RS256");
|
||||
properties.put(PROPERTY_SESSION_INTERVAL, 3600);
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.glance.v1_0;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
|
@ -65,7 +63,6 @@ public class GlanceApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.IMAGE);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.quantum.v1_0;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
|
@ -65,7 +63,6 @@ public class QuantumApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.NETWORK);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.openstack.swift.v1;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
|
||||
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
|
||||
|
||||
|
@ -65,7 +63,6 @@ public class SwiftApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(SERVICE_TYPE, ServiceType.OBJECT_STORE);
|
||||
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
|
||||
return properties;
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.opsource.servers;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -57,7 +54,6 @@ public class OpSourceServersApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.rds;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
|
||||
|
@ -61,7 +59,6 @@ public class RDSApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -22,23 +22,28 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
import static org.jclouds.Fallbacks.valOnNotFoundOr404;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
public final class RDSFallbacks {
|
||||
private RDSFallbacks() {
|
||||
}
|
||||
|
||||
public static final class NullOnStateDeletingNotFoundOr404 implements FutureFallback<Object> {
|
||||
public static final class NullOnStateDeletingNotFoundOr404 implements Fallback<Object> {
|
||||
@Override
|
||||
public ListenableFuture<Object> create(final Throwable t) {
|
||||
public ListenableFuture<Object> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof AWSResponseException) {
|
||||
AWSResponseException e = AWSResponseException.class.cast(t);
|
||||
if ("InvalidDBInstanceState".equals(e.getError().getCode())
|
||||
&& e.getError().getMessage().contains("has state: deleting"))
|
||||
return immediateFuture(null);
|
||||
return null;
|
||||
}
|
||||
return valOnNotFoundOr404(null, t);
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import java.net.URI;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.route53.config.Route53RestClientModule;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.rest.internal.BaseRestApiMetadata;
|
||||
import org.jclouds.route53.config.Route53RestClientModule;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
|
@ -59,7 +59,6 @@ public class Route53ApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.savvis.vpdc;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
import static org.jclouds.savvis.vpdc.reference.VPDCConstants.PROPERTY_VPDC_TIMEOUT_TASK_COMPLETED;
|
||||
|
||||
|
@ -62,8 +60,6 @@ public class VPDCApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "LoginApi.login", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_VPDC_TIMEOUT_TASK_COMPLETED, 600l * 1000l + "");
|
||||
return properties;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
*/
|
||||
package org.jclouds.vcloud.director.v1_5;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.PROPERTY_VCLOUD_DIRECTOR_TIMEOUT_TASK_COMPLETED;
|
||||
import static org.jclouds.vcloud.director.v1_5.VCloudDirectorConstants.PROPERTY_VCLOUD_DIRECTOR_VERSION_SCHEMA;
|
||||
|
@ -62,7 +60,6 @@ public class VCloudDirectorApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(3) + "");
|
||||
/** FIXME this should not be the default */
|
||||
properties.setProperty(PROPERTY_SESSION_INTERVAL, Integer.toString(30 * 60));
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.aws.ec2;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
|
||||
|
||||
import java.util.Properties;
|
||||
|
@ -63,9 +60,6 @@ public class AWSEC2ApiMetadata extends EC2ApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = EC2ApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ec2:DescribeImages", MINUTES.toMillis(5) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ec2:DescribeSpotInstanceRequests", MINUTES.toMillis(2) + "");
|
||||
properties.remove(PROPERTY_EC2_AMI_OWNERS);
|
||||
// auth fail sometimes happens in EC2, as the rc.local script that injects the
|
||||
// authorized key executes after ssh has started.
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.azureblob;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
|
@ -67,10 +65,6 @@ public class AzureBlobApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", MINUTES.toMillis(2) + "");
|
||||
// 10 minutes per MB * max size of 64M
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AzureBlobClient.putBlob", MINUTES.toMillis(10 * 64) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "AzureBlobClient.getBlob", MINUTES.toMillis(10 * 64) + "");
|
||||
properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "x-ms-meta-");
|
||||
return properties;
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
import static com.google.common.base.Throwables.propagate;
|
||||
import static com.google.common.util.concurrent.Futures.immediateFuture;
|
||||
|
||||
import org.jclouds.Fallback;
|
||||
import org.jclouds.azure.storage.AzureStorageResponseException;
|
||||
|
||||
import com.google.common.util.concurrent.FutureFallback;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
/**
|
||||
|
@ -35,14 +35,18 @@ public final class AzureBlobFallbacks {
|
|||
private AzureBlobFallbacks() {
|
||||
}
|
||||
|
||||
public static final class FalseIfContainerAlreadyExists implements FutureFallback<Boolean> {
|
||||
public static final class FalseIfContainerAlreadyExists implements Fallback<Boolean> {
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) throws Exception {
|
||||
return immediateFuture(createOrPropagate(t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<Boolean> create(Throwable t) {
|
||||
public Boolean createOrPropagate(Throwable t) throws Exception {
|
||||
if (checkNotNull(t, "throwable") instanceof AzureStorageResponseException) {
|
||||
AzureStorageResponseException responseException = AzureStorageResponseException.class.cast(t);
|
||||
if ("ContainerAlreadyExists".equals(responseException.getError().getCode())) {
|
||||
return immediateFuture(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
throw propagate(t);
|
||||
|
|
|
@ -34,8 +34,9 @@ import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.options.GetOptions;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.Invokable;
|
||||
|
||||
|
@ -45,7 +46,7 @@ import com.google.common.reflect.Invokable;
|
|||
*/
|
||||
@Singleton
|
||||
public class AzureBlobRequestSigner implements BlobRequestSigner {
|
||||
private final RestAnnotationProcessor processor;
|
||||
private final Function<Invocation, HttpRequest> processor;
|
||||
private final BlobToAzureBlob blobToBlob;
|
||||
private final BlobToHttpGetOptions blob2HttpGetOptions;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class AzureBlobRequestSigner implements BlobRequestSigner {
|
|||
private final Invokable<?, ?> createMethod;
|
||||
|
||||
@Inject
|
||||
public AzureBlobRequestSigner(RestAnnotationProcessor processor, BlobToAzureBlob blobToBlob,
|
||||
public AzureBlobRequestSigner(Function<Invocation, HttpRequest> processor, BlobToAzureBlob blobToBlob,
|
||||
BlobToHttpGetOptions blob2HttpGetOptions) throws SecurityException, NoSuchMethodException {
|
||||
this.processor = checkNotNull(processor, "processor");
|
||||
this.blobToBlob = checkNotNull(blobToBlob, "blobToBlob");
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.glesys;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -63,9 +60,6 @@ public class GleSYSApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(30) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ServerApi.createWithHostnameAndRootPassword", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ServerApi.clone", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty("jclouds.ssh.max-retries", "5");
|
||||
properties.setProperty("jclouds.ssh.retry-auth", "true");
|
||||
return properties;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.gogrid;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -62,7 +60,6 @@ public class GoGridApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
|
||||
properties.setProperty("jclouds.ssh.max-retries", "5");
|
||||
properties.setProperty("jclouds.ssh.retry-auth", "true");
|
||||
return properties;
|
||||
|
|
|
@ -51,9 +51,8 @@ import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
|
|||
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||
import org.jclouds.reflect.Invocation;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -69,7 +68,7 @@ import com.google.inject.Provider;
|
|||
@Singleton
|
||||
public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner {
|
||||
|
||||
private final RestAnnotationProcessor processor;
|
||||
private final Function<Invocation, HttpRequest> processor;
|
||||
private final Crypto crypto;
|
||||
|
||||
private final Provider<Long> unixEpochTimestampProvider;
|
||||
|
@ -84,7 +83,7 @@ public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner
|
|||
private final Invokable<?, ?> createMethod;
|
||||
|
||||
@Inject
|
||||
public HPCloudObjectStorageBlobRequestSigner(RestAnnotationProcessor processor,
|
||||
public HPCloudObjectStorageBlobRequestSigner(Function<Invocation, HttpRequest> processor,
|
||||
BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto,
|
||||
@TimeStamp Provider<Long> unixEpochTimestampProvider, Supplier<Access> access,
|
||||
@org.jclouds.location.Provider final Supplier<Credentials> creds) throws SecurityException,
|
||||
|
@ -115,8 +114,7 @@ public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner
|
|||
public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
|
||||
checkNotNull(container, "container");
|
||||
checkNotNull(name, "name");
|
||||
GeneratedHttpRequest request = processor.apply(Invocation.create(getMethod,
|
||||
ImmutableList.<Object> of(container, name)));
|
||||
HttpRequest request = processor.apply(Invocation.create(getMethod, ImmutableList.<Object> of(container, name)));
|
||||
return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
|
||||
}
|
||||
|
||||
|
@ -140,7 +138,7 @@ public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner
|
|||
public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
|
||||
checkNotNull(container, "container");
|
||||
checkNotNull(blob, "blob");
|
||||
GeneratedHttpRequest request = processor.apply(Invocation.create(createMethod,
|
||||
HttpRequest request = processor.apply(Invocation.create(createMethod,
|
||||
ImmutableList.<Object> of(container, blobToObject.apply(blob))));
|
||||
return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
*/
|
||||
package org.jclouds.softlayer;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX;
|
||||
import static org.jclouds.reflect.Reflection2.typeToken;
|
||||
|
||||
import java.net.URI;
|
||||
|
@ -63,8 +60,6 @@ public class SoftLayerApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "default", SECONDS.toMillis(90) + "");
|
||||
properties.setProperty(PROPERTY_TIMEOUTS_PREFIX + "ProductPackageClient", MINUTES.toMillis(3) + "");
|
||||
properties.setProperty("jclouds.ssh.max-retries", "5");
|
||||
properties.setProperty("jclouds.ssh.retry-auth", "true");
|
||||
return properties;
|
||||
|
|
Loading…
Reference in New Issue