diff --git a/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java b/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java index 4efaf99ac4..9517e6c12e 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java +++ b/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java @@ -21,6 +21,7 @@ package org.jclouds.s3.config; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; import javax.inject.Named; import javax.inject.Singleton; @@ -33,6 +34,7 @@ import org.jclouds.http.RequiresHttp; import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.ServerError; +import org.jclouds.location.Region; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.RequestSigner; import org.jclouds.s3.Bucket; @@ -70,6 +72,14 @@ public class S3RestClientModule ext return Maps.newConcurrentMap(); } + @Provides + @Bucket + @Singleton + @Nullable + protected String defaultRegionForBucket(@Nullable @Region String defaultRegion) { + return defaultRegion; + } + @Override protected void configure() { install(new S3ObjectModule()); diff --git a/apis/s3/src/main/java/org/jclouds/s3/functions/BindRegionToXmlPayload.java b/apis/s3/src/main/java/org/jclouds/s3/functions/BindRegionToXmlPayload.java index 4668ec06f9..c634bf5388 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/functions/BindRegionToXmlPayload.java +++ b/apis/s3/src/main/java/org/jclouds/s3/functions/BindRegionToXmlPayload.java @@ -19,9 +19,8 @@ package org.jclouds.s3.functions; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; -import java.net.URI; -import java.util.Map; import java.util.Set; import javax.annotation.Nullable; @@ -33,11 +32,12 @@ import javax.ws.rs.core.MediaType; import org.jclouds.http.HttpRequest; import org.jclouds.logging.Logger; import org.jclouds.rest.binders.BindToStringPayload; +import org.jclouds.s3.Bucket; /** * - * Depending on your latency and legal requirements, you can specify a location constraint that will - * affect where your data physically resides. + * Depending on your latency and legal requirements, you can specify a location + * constraint that will affect where your data physically resides. * * @author Adrian Cole * @@ -47,25 +47,28 @@ public class BindRegionToXmlPayload extends BindToStringPayload { @Resource protected Logger logger = Logger.NULL; - private final String defaultRegion; + private final String defaultRegionForEndpoint; + private final String defaultRegionForService; private final Set regions; @Inject - BindRegionToXmlPayload(@org.jclouds.location.Region @Nullable String defaultRegion, - @org.jclouds.location.Region Set regions) { - this.defaultRegion = defaultRegion; - this.regions = regions; + public BindRegionToXmlPayload(@org.jclouds.location.Region @Nullable String defaultRegionForEndpoint, + @Nullable @Bucket String defaultRegionForService, @org.jclouds.location.Region Set regions) { + this.defaultRegionForEndpoint = defaultRegionForEndpoint; + this.defaultRegionForService = defaultRegionForService; + this.regions = checkNotNull(regions, "regions"); } @Override public R bindToRequest(R request, Object input) { - if (defaultRegion == null) + if (defaultRegionForEndpoint == null) return request; - input = input == null ? defaultRegion : input; + input = input == null ? defaultRegionForEndpoint : input; checkArgument(input instanceof String, "this binder is only valid for Region!"); String constraint = (String) input; String value = null; - if (defaultRegion.equals(constraint)) { + if ((defaultRegionForService == null && constraint == null) + || (defaultRegionForService != null && defaultRegionForService.equals(constraint))) { // nothing to bind as this is default. return request; } else if (regions.contains(constraint)) { @@ -74,9 +77,10 @@ public class BindRegionToXmlPayload extends BindToStringPayload { logger.warn("region %s not in %s ", constraint, regions); value = constraint; } - String payload = String.format( - "%s", - value); + String payload = String + .format( + "%s", + value); request = super.bindToRequest(request, payload); request.getPayload().getContentMetadata().setContentType(MediaType.TEXT_XML); return request; diff --git a/apis/s3/src/main/java/org/jclouds/s3/xml/LocationConstraintHandler.java b/apis/s3/src/main/java/org/jclouds/s3/xml/LocationConstraintHandler.java index 6d9f1c25f6..e3ffabc7ef 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/xml/LocationConstraintHandler.java +++ b/apis/s3/src/main/java/org/jclouds/s3/xml/LocationConstraintHandler.java @@ -20,7 +20,7 @@ package org.jclouds.s3.xml; import static org.jclouds.util.SaxUtils.currentOrNull; -import java.util.concurrent.ConcurrentMap; +import java.util.Map; import javax.inject.Inject; @@ -35,17 +35,19 @@ import org.jclouds.s3.Bucket; *

* Region is the document we expect to parse. * - * @see + * @see * @author Adrian Cole */ public class LocationConstraintHandler extends ParseSax.HandlerWithResult { - private final ConcurrentMap bucketToRegion; + private final Map bucketToRegion; private StringBuilder currentText = new StringBuilder(); private String region; private String bucket; @Inject - public LocationConstraintHandler(@Bucket ConcurrentMap bucketToRegion) { + public LocationConstraintHandler(@Bucket Map bucketToRegion) { this.bucketToRegion = bucketToRegion; } diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/binders/AssignCorrectHostnameAndBindAsHostPrefixIfConfigured.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/binders/AssignCorrectHostnameAndBindAsHostPrefixIfConfigured.java new file mode 100644 index 0000000000..20c5abd042 --- /dev/null +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/binders/AssignCorrectHostnameAndBindAsHostPrefixIfConfigured.java @@ -0,0 +1,73 @@ +/** + * + * Copyright (C) 2011 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.s3.binders; + +import static org.jclouds.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH; +import static org.jclouds.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; +import javax.ws.rs.core.UriBuilder; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.utils.ModifyRequest; +import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; +import org.jclouds.rest.binders.BindAsHostPrefix; +import org.jclouds.s3.Bucket; +import org.jclouds.s3.binders.BindAsHostPrefixIfConfigured; + +/** + * + * @author Adrian Cole + */ +@Singleton +public class AssignCorrectHostnameAndBindAsHostPrefixIfConfigured extends BindAsHostPrefixIfConfigured { + private final Map bucketToRegion; + private final RegionToEndpointOrProviderIfNull r2; + + @Inject + public AssignCorrectHostnameAndBindAsHostPrefixIfConfigured(BindAsHostPrefix bindAsHostPrefix, + @Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle, + @Named(PROPERTY_S3_SERVICE_PATH) String servicePath, RegionToEndpointOrProviderIfNull r2, + Provider uriBuilderProvider, @Bucket Map bucketToRegion) { + super(bindAsHostPrefix, isVhostStyle, servicePath, uriBuilderProvider); + this.bucketToRegion = bucketToRegion; + this.r2 = r2; + } + + @Override + public R bindToRequest(R request, Object payload) { + String bucket = payload.toString(); + String region = bucketToRegion.get(bucket); + if (region != null) { + URI endpoint = r2.apply(region); + request = ModifyRequest.endpoint( + request, + uriBuilderProvider.get().uri(endpoint).path(request.getEndpoint().getPath()) + .replaceQuery(request.getEndpoint().getQuery()).build()); + } + return super.bindToRequest(request, payload); + } +} diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java index b2b8465fed..daccd2d7ed 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java @@ -31,6 +31,7 @@ import org.jclouds.aws.s3.AWSS3AsyncClient; import org.jclouds.aws.s3.AWSS3Client; import org.jclouds.aws.s3.binders.AssignCorrectHostnameAndBindAsHostPrefixIfConfigured; import org.jclouds.http.RequiresHttp; +import org.jclouds.location.Region; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.s3.Bucket; import org.jclouds.s3.S3AsyncClient; @@ -52,10 +53,15 @@ public class AWSS3RestClientModule extends S3RestClientModule { @@ -70,11 +70,11 @@ public class AWSS3AsyncClientTest extends org.jclouds.s3.S3AsyncClientTest> createTypeLiteral() { return new TypeLiteral>() { @@ -107,7 +149,8 @@ public class AWSS3AsyncClientTest extends org.jclouds.s3.S3AsyncClientTestEU", "text/xml", false); @@ -214,8 +257,8 @@ public class AWSS3AsyncClientTest extends org.jclouds.s3.S3AsyncClientTest