diff --git a/atmosonline/saas/core/src/main/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModule.java b/atmosonline/saas/core/src/main/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModule.java index 09511eec92..157ae74f9c 100644 --- a/atmosonline/saas/core/src/main/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModule.java +++ b/atmosonline/saas/core/src/main/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModule.java @@ -27,7 +27,6 @@ import static org.jclouds.atmosonline.saas.reference.AtmosStorageConstants.PROPE import static org.jclouds.atmosonline.saas.reference.AtmosStorageConstants.PROPERTY_EMCSAAS_SESSIONINTERVAL; import java.net.URI; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import javax.inject.Named; @@ -37,6 +36,7 @@ import org.jclouds.atmosonline.saas.AtmosStorage; import org.jclouds.atmosonline.saas.AtmosStorageClient; import org.jclouds.atmosonline.saas.handlers.AtmosStorageClientErrorRetryHandler; import org.jclouds.atmosonline.saas.handlers.ParseAtmosStorageErrorFromXmlContent; +import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpRetryHandler; import org.jclouds.http.RequiresHttp; @@ -48,8 +48,7 @@ import org.jclouds.rest.RestClientFactory; import org.jclouds.util.DateService; import org.jclouds.util.TimeStamp; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -82,8 +81,8 @@ public class AtmosStorageRestClientModule extends AbstractModule { @Provides @TimeStamp - protected String provideTimeStamp(@TimeStamp ConcurrentMap cache) { - return cache.get("doesn't matter"); + protected String provideTimeStamp(@TimeStamp Supplier cache) { + return cache.get(); } /** @@ -91,14 +90,13 @@ public class AtmosStorageRestClientModule extends AbstractModule { */ @Provides @TimeStamp - ConcurrentMap provideTimeStampCache( - @Named(PROPERTY_EMCSAAS_SESSIONINTERVAL) long seconds, final DateService dateService) { - return new MapMaker().expiration(seconds, TimeUnit.SECONDS).makeComputingMap( - new Function() { - public String apply(String key) { - return dateService.rfc822DateFormat(); - } - }); + Supplier provideTimeStampCache(@Named(PROPERTY_EMCSAAS_SESSIONINTERVAL) long seconds, + final DateService dateService) { + return new ExpirableSupplier(new Supplier() { + public String get() { + return dateService.rfc822DateFormat(); + } + }, seconds, TimeUnit.SECONDS); } protected void bindErrorHandlers() { diff --git a/atmosonline/saas/core/src/test/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModuleTest.java b/atmosonline/saas/core/src/test/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModuleTest.java index 7ae2729b93..c74296dfec 100644 --- a/atmosonline/saas/core/src/test/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModuleTest.java +++ b/atmosonline/saas/core/src/test/java/org/jclouds/atmosonline/saas/config/AtmosStorageRestClientModuleTest.java @@ -26,8 +26,6 @@ package org.jclouds.atmosonline.saas.config; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import java.util.concurrent.ConcurrentMap; - import org.bouncycastle.util.encoders.Base64; import org.jclouds.atmosonline.saas.handlers.AtmosStorageClientErrorRetryHandler; import org.jclouds.atmosonline.saas.handlers.ParseAtmosStorageErrorFromXmlContent; @@ -42,6 +40,7 @@ import org.jclouds.util.DateService; import org.jclouds.util.Jsr330; import org.testng.annotations.Test; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -74,13 +73,13 @@ public class AtmosStorageRestClientModuleTest { void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException { AtmosStorageRestClientModule module = new AtmosStorageRestClientModule(); - ConcurrentMap map = module.provideTimeStampCache(1, new DateService()); - String timeStamp = map.get("foo"); + Supplier map = module.provideTimeStampCache(1, new DateService()); + String timeStamp = map.get(); for (int i = 0; i < 10; i++) - map.get("foo"); - assertEquals(timeStamp, map.get("foo")); + map.get(); + assertEquals(timeStamp, map.get()); Thread.sleep(1001); - assertFalse(timeStamp.equals(map.get("foo"))); + assertFalse(timeStamp.equals(map.get())); } @Test diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/S3PropertiesBuilder.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/S3PropertiesBuilder.java index 871c37e50a..1ddba6e5ea 100644 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/S3PropertiesBuilder.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/S3PropertiesBuilder.java @@ -26,8 +26,11 @@ package org.jclouds.aws.s3; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_ACCESSKEYID; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AWS_SECRETACCESSKEY; +import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_ENDPOINT; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_METADATA_PREFIX; +import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_RETRY; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SESSIONINTERVAL; +import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_TIMEOUT; import java.net.URI; import java.util.Properties; @@ -44,7 +47,7 @@ public class S3PropertiesBuilder extends HttpPropertiesBuilder { @Override protected Properties defaultProperties() { Properties properties = super.defaultProperties(); - properties.setProperty(S3Constants.PROPERTY_S3_ENDPOINT, "https://s3.amazonaws.com"); + properties.setProperty(PROPERTY_S3_ENDPOINT, "https://s3.amazonaws.com"); properties.setProperty(PROPERTY_S3_METADATA_PREFIX, "x-amz-meta-"); properties.setProperty(PROPERTY_S3_SESSIONINTERVAL, "60"); return properties; @@ -77,4 +80,24 @@ public class S3PropertiesBuilder extends HttpPropertiesBuilder { return this; } + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public S3PropertiesBuilder withRequestTimeout(long milliseconds) { + properties.setProperty(PROPERTY_S3_TIMEOUT, Long.toString(milliseconds)); + return this; + } + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public S3PropertiesBuilder withMaxRetries(int retries) { + properties.setProperty(PROPERTY_S3_RETRY, Integer.toString(retries)); + return this; + } + + protected S3PropertiesBuilder withMetaPrefix(String prefix) { + properties.setProperty(PROPERTY_S3_METADATA_PREFIX, prefix); + return this; + } } diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilder.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilder.java index 0b8651087d..2927d203cf 100755 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilder.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilder.java @@ -23,8 +23,11 @@ */ package org.jclouds.aws.s3.blobstore; +import static org.jclouds.aws.s3.reference.S3Constants.*; +import static org.jclouds.blobstore.reference.BlobStoreConstants.*; import java.util.List; import java.util.Properties; +import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import org.jclouds.aws.s3.S3Client; @@ -34,6 +37,7 @@ import org.jclouds.blobstore.BlobStoreContextBuilder; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; +import com.google.common.collect.ImmutableMap; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.TypeLiteral; @@ -55,7 +59,17 @@ public class S3BlobStoreContextBuilder extends BlobStoreContextBuilder public S3BlobStoreContextBuilder(Properties props) { super(new TypeLiteral() { - }, props); + }, convert(props)); + } + + private static Properties convert(Properties props) { + for (Entry entry : ImmutableMap.of(PROPERTY_S3_METADATA_PREFIX, + PROPERTY_USER_METADATA_PREFIX, PROPERTY_S3_RETRY, PROPERTY_BLOBSTORE_RETRY, + PROPERTY_S3_TIMEOUT, PROPERTY_USER_METADATA_PREFIX).entrySet()) { + if (props.containsKey(entry.getKey())) + props.setProperty(entry.getValue(), props.getProperty(entry.getKey())); + } + return props; } @Override diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextFactory.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextFactory.java index d732ac7b33..f106f923f6 100755 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextFactory.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextFactory.java @@ -27,6 +27,7 @@ import java.net.URI; import java.util.Properties; import org.jclouds.aws.s3.S3Client; +import org.jclouds.aws.s3.S3PropertiesBuilder; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; @@ -47,19 +48,19 @@ import com.google.inject.Module; */ public class S3BlobStoreContextFactory { public static BlobStoreContext createContext(Properties properties, Module... modules) { - return new S3BlobStoreContextBuilder(new S3BlobStorePropertiesBuilder(properties).build()) + return new S3BlobStoreContextBuilder(new S3PropertiesBuilder(properties).build()) .withModules(modules).buildContext(); } public static BlobStoreContext createContext(String awsAccessKeyId, String awsSecretAccessKey, Module... modules) { - return new S3BlobStoreContextBuilder(new S3BlobStorePropertiesBuilder(awsAccessKeyId, + return new S3BlobStoreContextBuilder(new S3PropertiesBuilder(awsAccessKeyId, awsSecretAccessKey).build()).withModules(modules).buildContext(); } public static BlobStoreContext createContext(URI endpoint, String awsAccessKeyId, String awsSecretAccessKey, Module... modules) { - return new S3BlobStoreContextBuilder(new S3BlobStorePropertiesBuilder(awsAccessKeyId, + return new S3BlobStoreContextBuilder(new S3PropertiesBuilder(awsAccessKeyId, awsSecretAccessKey).withEndpoint(endpoint).build()).withModules(modules) .buildContext(); } diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStorePropertiesBuilder.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStorePropertiesBuilder.java deleted file mode 100644 index 75d571505b..0000000000 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStorePropertiesBuilder.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * - * Copyright (C) 2009 Cloud Conscious, LLC. - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ -package org.jclouds.aws.s3.blobstore; - -import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; - -import java.util.Properties; - -import org.jclouds.aws.s3.S3PropertiesBuilder; -import org.jclouds.blobstore.reference.BlobStoreConstants; - -/** - * Builds properties used in S3 Blob Stores - * - * @author Adrian Cole, Andrew Newdigate - */ -public class S3BlobStorePropertiesBuilder extends S3PropertiesBuilder { - - public S3BlobStorePropertiesBuilder(String id, String secret) { - super(id, secret); - } - - public S3BlobStorePropertiesBuilder(Properties properties) { - super(properties); - } - - /** - * longest time a single synchronous operation can take before throwing an exception. - */ - public S3BlobStorePropertiesBuilder withRequestTimeout(long milliseconds) { - properties.setProperty(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT, Long - .toString(milliseconds)); - return this; - } - - @Override - protected Properties defaultProperties() { - Properties props = super.defaultProperties(); - props.setProperty(PROPERTY_USER_METADATA_PREFIX, "x-amz-meta-"); - return props; - } -} diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/S3RestClientModule.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/S3RestClientModule.java index 33dd1da18f..8b390bc09a 100755 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/S3RestClientModule.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/config/S3RestClientModule.java @@ -24,7 +24,6 @@ package org.jclouds.aws.s3.config; import java.net.URI; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import javax.inject.Named; @@ -37,6 +36,7 @@ import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler; import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent; import org.jclouds.aws.s3.reference.S3Constants; +import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpRetryHandler; import org.jclouds.http.RequiresHttp; @@ -48,8 +48,7 @@ import org.jclouds.rest.RestClientFactory; import org.jclouds.util.DateService; import org.jclouds.util.TimeStamp; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Scopes; @@ -65,8 +64,8 @@ public class S3RestClientModule extends AbstractModule { @Provides @TimeStamp - protected String provideTimeStamp(@TimeStamp ConcurrentMap cache) { - return cache.get("doesn't matter"); + protected String provideTimeStamp(@TimeStamp Supplier cache) { + return cache.get(); } /** @@ -74,15 +73,14 @@ public class S3RestClientModule extends AbstractModule { */ @Provides @TimeStamp - ConcurrentMap provideTimeStampCache( + Supplier provideTimeStampCache( @Named(S3Constants.PROPERTY_S3_SESSIONINTERVAL) long seconds, final DateService dateService) { - return new MapMaker().expiration(seconds, TimeUnit.SECONDS).makeComputingMap( - new Function() { - public String apply(String key) { - return dateService.rfc822DateFormat(); - } - }); + return new ExpirableSupplier(new Supplier() { + public String get() { + return dateService.rfc822DateFormat(); + } + }, seconds, TimeUnit.SECONDS); } @Override diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/functions/ObjectKey.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/functions/ObjectKey.java index 50f135aa2d..769a98038f 100644 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/functions/ObjectKey.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/functions/ObjectKey.java @@ -23,6 +23,8 @@ */ package org.jclouds.aws.s3.functions; +import javax.inject.Singleton; + import org.jclouds.aws.s3.domain.S3Object; import com.google.common.base.Function; @@ -31,6 +33,7 @@ import com.google.common.base.Function; * * @author Adrian Cole */ +@Singleton public class ObjectKey implements Function { public String apply(Object from) { diff --git a/aws/s3/core/src/main/java/org/jclouds/aws/s3/reference/S3Constants.java b/aws/s3/core/src/main/java/org/jclouds/aws/s3/reference/S3Constants.java index ce979259b0..da40704f57 100644 --- a/aws/s3/core/src/main/java/org/jclouds/aws/s3/reference/S3Constants.java +++ b/aws/s3/core/src/main/java/org/jclouds/aws/s3/reference/S3Constants.java @@ -46,6 +46,19 @@ public interface S3Constants extends AWSConstants, S3Headers { * how long do we wait before obtaining a new timestamp for requests. */ public static final String PROPERTY_S3_SESSIONINTERVAL = "jclouds.s3.sessioninterval"; + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public static final String PROPERTY_S3_TIMEOUT = "jclouds.s3.timeout"; + /** + * time to pause before retrying a transient failure + */ + public static final String PROPERTY_S3_RETRY = "jclouds.s3.retry"; + /** + * Any header starting with this prefix is considered user metadata. It will be stored with the + * object and returned when you retrieve the object/ + */ public static final String PROPERTY_S3_METADATA_PREFIX = "jclouds.s3.metaprefix"; } diff --git a/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilderTest.java b/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilderTest.java index 5d6e9ee4c4..2ebbd354a0 100644 --- a/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilderTest.java +++ b/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/S3BlobStoreContextBuilderTest.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; import org.jclouds.aws.s3.S3Client; +import org.jclouds.aws.s3.S3PropertiesBuilder; import org.jclouds.aws.s3.blobstore.config.S3BlobStoreContextModule; import org.jclouds.aws.s3.config.S3RestClientModule; import org.jclouds.aws.s3.config.S3StubClientModule; @@ -59,8 +60,8 @@ import com.google.inject.TypeLiteral; public class S3BlobStoreContextBuilderTest { public void testNewBuilder() { - S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder( - new S3BlobStorePropertiesBuilder("id", "secret").build()); + S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder(new S3PropertiesBuilder( + "id", "secret").build()); assertEquals(builder.getProperties().getProperty(PROPERTY_USER_METADATA_PREFIX), "x-amz-meta-"); assertEquals(builder.getProperties().getProperty(PROPERTY_AWS_ACCESSKEYID), "id"); @@ -68,9 +69,8 @@ public class S3BlobStoreContextBuilderTest { } public void testBuildContext() { - BlobStoreContext context = new S3BlobStoreContextBuilder( - new S3BlobStorePropertiesBuilder("id", "secret").build()).withModules( - new S3StubClientModule()).buildContext(); + BlobStoreContext context = new S3BlobStoreContextBuilder(new S3PropertiesBuilder( + "id", "secret").build()).withModules(new S3StubClientModule()).buildContext(); assertEquals(context.getClass(), BlobStoreContextImpl.class); assertEquals(context.getApi().getClass(), StubS3Client.class); assertEquals(context.getBlobStore().getClass(), S3BlobStore.class); @@ -81,8 +81,8 @@ public class S3BlobStoreContextBuilderTest { } public void testBuildInjector() { - Injector i = new S3BlobStoreContextBuilder(new S3BlobStorePropertiesBuilder("id", "secret") - .build()).withModules(new S3StubClientModule()).buildInjector(); + Injector i = new S3BlobStoreContextBuilder(new S3PropertiesBuilder("id", "secret").build()) + .withModules(new S3StubClientModule()).buildInjector(); assert i.getInstance(Key.get(new TypeLiteral>() { })) != null; assert i.getInstance(S3Object.class) != null; @@ -91,8 +91,8 @@ public class S3BlobStoreContextBuilderTest { protected void testAddContextModule() { List modules = new ArrayList(); - S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder( - new S3BlobStorePropertiesBuilder("id", "secret").build()); + S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder(new S3PropertiesBuilder( + "id", "secret").build()); builder.addContextModule(modules); assertEquals(modules.size(), 1); assertEquals(modules.get(0).getClass(), S3BlobStoreContextModule.class); @@ -100,8 +100,8 @@ public class S3BlobStoreContextBuilderTest { protected void addClientModule() { List modules = new ArrayList(); - S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder( - new S3BlobStorePropertiesBuilder("id", "secret").build()); + S3BlobStoreContextBuilder builder = new S3BlobStoreContextBuilder(new S3PropertiesBuilder( + "id", "secret").build()); builder.addClientModule(modules); assertEquals(modules.size(), 1); assertEquals(modules.get(0).getClass(), S3RestClientModule.class); diff --git a/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/integration/S3TestInitializer.java b/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/integration/S3TestInitializer.java index 4662f836ac..26166d2b77 100644 --- a/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/integration/S3TestInitializer.java +++ b/aws/s3/core/src/test/java/org/jclouds/aws/s3/blobstore/integration/S3TestInitializer.java @@ -24,9 +24,9 @@ package org.jclouds.aws.s3.blobstore.integration; import org.jclouds.aws.s3.S3Client; +import org.jclouds.aws.s3.S3PropertiesBuilder; import org.jclouds.aws.s3.blobstore.S3BlobStoreContextBuilder; import org.jclouds.aws.s3.blobstore.S3BlobStoreContextFactory; -import org.jclouds.aws.s3.blobstore.S3BlobStorePropertiesBuilder; import org.jclouds.aws.s3.config.S3StubClientModule; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest; @@ -45,9 +45,8 @@ public class S3TestInitializer extends BaseTestInitializer { protected BlobStoreContext createLiveContext(Module configurationModule, String url, String app, String account, String key) { BaseBlobStoreIntegrationTest.SANITY_CHECK_RETURNED_BUCKET_NAME = true; - return new S3BlobStoreContextBuilder(new S3BlobStorePropertiesBuilder(account, key) - .relaxSSLHostname().build()).withModules(configurationModule, - new Log4JLoggingModule()).buildContext(); + return new S3BlobStoreContextBuilder(new S3PropertiesBuilder(account, key).relaxSSLHostname() + .build()).withModules(configurationModule, new Log4JLoggingModule()).buildContext(); } @Override diff --git a/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3RestClientModuleTest.java b/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3RestClientModuleTest.java index 523715684a..7c495d7172 100644 --- a/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3RestClientModuleTest.java +++ b/aws/s3/core/src/test/java/org/jclouds/aws/s3/config/S3RestClientModuleTest.java @@ -26,8 +26,6 @@ package org.jclouds.aws.s3.config; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import java.util.concurrent.ConcurrentMap; - import org.jclouds.aws.s3.handlers.AWSClientErrorRetryHandler; import org.jclouds.aws.s3.handlers.AWSRedirectionRetryHandler; import org.jclouds.aws.s3.handlers.ParseAWSErrorFromXmlContent; @@ -41,6 +39,7 @@ import org.jclouds.util.DateService; import org.jclouds.util.Jsr330; import org.testng.annotations.Test; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -72,13 +71,13 @@ public class S3RestClientModuleTest { void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException { S3RestClientModule module = new S3RestClientModule(); - ConcurrentMap map = module.provideTimeStampCache(1, new DateService()); - String timeStamp = map.get("foo"); + Supplier map = module.provideTimeStampCache(1, new DateService()); + String timeStamp = map.get(); for (int i = 0; i < 10; i++) - map.get("foo"); - assertEquals(timeStamp, map.get("foo")); + map.get(); + assertEquals(timeStamp, map.get()); Thread.sleep(1001); - assertFalse(timeStamp.equals(map.get("foo"))); + assertFalse(timeStamp.equals(map.get())); } @Test diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/AzureBlobPropertiesBuilder.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/AzureBlobPropertiesBuilder.java index a46f959d65..0d0a132d8c 100644 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/AzureBlobPropertiesBuilder.java +++ b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/AzureBlobPropertiesBuilder.java @@ -24,14 +24,19 @@ package org.jclouds.azure.storage.blob; import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_METADATA_PREFIX; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_RETRY; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_SESSIONINTERVAL; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_TIMEOUT; +import static org.jclouds.azure.storage.reference.AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT; +import static org.jclouds.azure.storage.reference.AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY; import static org.jclouds.azure.storage.reference.AzureStorageConstants.PROPERTY_AZURESTORAGE_SESSIONINTERVAL; +import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import java.net.URI; import java.util.Properties; -import org.jclouds.azure.storage.blob.reference.AzureBlobConstants; -import org.jclouds.azure.storage.reference.AzureStorageConstants; -import org.jclouds.blobstore.reference.BlobStoreConstants; import org.jclouds.http.HttpPropertiesBuilder; /** @@ -43,10 +48,10 @@ public class AzureBlobPropertiesBuilder extends HttpPropertiesBuilder { @Override protected Properties defaultProperties() { Properties properties = super.defaultProperties(); - properties.setProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT, - "https://{account}.blob.core.windows.net"); - properties.setProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_METADATA_PREFIX, "x-ms-meta-"); - properties.setProperty(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX, "x-ms-meta-"); + properties + .setProperty(PROPERTY_AZUREBLOB_ENDPOINT, "https://{account}.blob.core.windows.net"); + properties.setProperty(PROPERTY_AZUREBLOB_METADATA_PREFIX, "x-ms-meta-"); + properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "x-ms-meta-"); properties.setProperty(PROPERTY_AZURESTORAGE_SESSIONINTERVAL, 60 + ""); return properties; } @@ -61,29 +66,48 @@ public class AzureBlobPropertiesBuilder extends HttpPropertiesBuilder { } public AzureBlobPropertiesBuilder withCredentials(String id, String secret) { - properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id, - "azureStorageAccount")); - properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY, checkNotNull(secret, - "azureStorageKey")); - String endpoint = properties.getProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT); - properties.setProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT, endpoint.replaceAll( - "\\{account\\}", id)); + properties + .setProperty(PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id, "azureStorageAccount")); + properties.setProperty(PROPERTY_AZURESTORAGE_KEY, checkNotNull(secret, "azureStorageKey")); + String endpoint = properties.getProperty(PROPERTY_AZUREBLOB_ENDPOINT); + properties.setProperty(PROPERTY_AZUREBLOB_ENDPOINT, endpoint.replaceAll("\\{account\\}", id)); return this; } public AzureBlobPropertiesBuilder withEndpoint(URI endpoint) { - String account = checkNotNull(properties - .getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT), + String account = checkNotNull(properties.getProperty(PROPERTY_AZURESTORAGE_ACCOUNT), "azureStorageAccount"); - properties.setProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT, checkNotNull(endpoint, - "endpoint").toString()); - properties.setProperty(AzureBlobConstants.PROPERTY_AZUREBLOB_ENDPOINT, endpoint.toString() - .replaceAll("\\{account\\}", account)); + properties.setProperty(PROPERTY_AZUREBLOB_ENDPOINT, checkNotNull(endpoint, "endpoint") + .toString()); + properties.setProperty(PROPERTY_AZUREBLOB_ENDPOINT, endpoint.toString().replaceAll( + "\\{account\\}", account)); return this; } public AzureBlobPropertiesBuilder withTimeStampExpiration(long seconds) { - properties.setProperty(PROPERTY_AZURESTORAGE_SESSIONINTERVAL, seconds + ""); + properties.setProperty(PROPERTY_AZUREBLOB_SESSIONINTERVAL, seconds + ""); + return this; + } + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public AzureBlobPropertiesBuilder withRequestTimeout(long milliseconds) { + properties.setProperty(PROPERTY_AZUREBLOB_TIMEOUT, Long.toString(milliseconds)); + return this; + } + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public AzureBlobPropertiesBuilder withMaxRetries(int retries) { + properties.setProperty(PROPERTY_AZUREBLOB_RETRY, Integer.toString(retries)); + return this; + } + + protected AzureBlobPropertiesBuilder withMetaPrefix(String prefix) { + properties.setProperty(PROPERTY_AZUREBLOB_METADATA_PREFIX, prefix); + properties.setProperty(PROPERTY_USER_METADATA_PREFIX, prefix); return this; } diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/binders/BindAzureBlobToEntity.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/binders/BindAzureBlobToEntity.java index 3260e8f0e2..9ec116d2c4 100644 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/binders/BindAzureBlobToEntity.java +++ b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/binders/BindAzureBlobToEntity.java @@ -23,26 +23,27 @@ */ package org.jclouds.azure.storage.blob.binders; -import static com.google.common.base.Preconditions.*; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import javax.inject.Inject; +import javax.inject.Named; import javax.ws.rs.core.HttpHeaders; import org.jclouds.azure.storage.blob.blobstore.functions.AzureBlobToBlob; import org.jclouds.azure.storage.blob.domain.AzureBlob; +import org.jclouds.azure.storage.blob.reference.AzureBlobConstants; import org.jclouds.blobstore.binders.BindBlobToEntityAndUserMetadataToHeadersWithPrefix; import org.jclouds.http.HttpRequest; -import org.jclouds.rest.Binder; -public class BindAzureBlobToEntity implements Binder { +public class BindAzureBlobToEntity extends BindBlobToEntityAndUserMetadataToHeadersWithPrefix { - private final BindBlobToEntityAndUserMetadataToHeadersWithPrefix blobBinder; private final AzureBlobToBlob azureBlob2Blob; @Inject public BindAzureBlobToEntity(AzureBlobToBlob azureBlob2Blob, - BindBlobToEntityAndUserMetadataToHeadersWithPrefix blobBinder) { - this.blobBinder = blobBinder; + @Named(AzureBlobConstants.PROPERTY_AZUREBLOB_METADATA_PREFIX) String prefix) { + super(prefix); this.azureBlob2Blob = azureBlob2Blob; } @@ -52,7 +53,7 @@ public class BindAzureBlobToEntity implements Binder { checkArgument( checkNotNull(object.getContentLength(), "object.getContentLength()") <= 64 * 1024 * 1024, "maximum size for put Blob is 64MB"); - blobBinder.bindToRequest(request, azureBlob2Blob.apply(object)); + super.bindToRequest(request, azureBlob2Blob.apply(object)); if (object.getProperties().getContentLanguage() != null) { request.getHeaders().put(HttpHeaders.CONTENT_LANGUAGE, diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilder.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilder.java index dc037706bf..73a21a67b4 100755 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilder.java +++ b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilder.java @@ -23,8 +23,15 @@ */ package org.jclouds.azure.storage.blob.blobstore; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_METADATA_PREFIX; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_RETRY; +import static org.jclouds.azure.storage.blob.reference.AzureBlobConstants.PROPERTY_AZUREBLOB_TIMEOUT; +import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_BLOBSTORE_RETRY; +import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; + import java.util.List; import java.util.Properties; +import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import org.jclouds.azure.storage.blob.AzureBlobClient; @@ -34,6 +41,7 @@ import org.jclouds.blobstore.BlobStoreContextBuilder; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; +import com.google.common.collect.ImmutableMap; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.TypeLiteral; @@ -55,7 +63,17 @@ public class AzureBlobStoreContextBuilder extends BlobStoreContextBuilder() { - }, props); + }, convert(props)); + } + + private static Properties convert(Properties props) { + for (Entry entry : ImmutableMap.of(PROPERTY_AZUREBLOB_METADATA_PREFIX, + PROPERTY_USER_METADATA_PREFIX, PROPERTY_AZUREBLOB_RETRY, PROPERTY_BLOBSTORE_RETRY, + PROPERTY_AZUREBLOB_TIMEOUT, PROPERTY_USER_METADATA_PREFIX).entrySet()) { + if (props.containsKey(entry.getKey())) + props.setProperty(entry.getValue(), props.getProperty(entry.getKey())); + } + return props; } @Override diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextFactory.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextFactory.java index a6fc9d3e0b..d2ae99e8e2 100755 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextFactory.java +++ b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextFactory.java @@ -27,6 +27,7 @@ import java.net.URI; import java.util.Properties; import org.jclouds.azure.storage.blob.AzureBlobClient; +import org.jclouds.azure.storage.blob.AzureBlobPropertiesBuilder; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; @@ -34,8 +35,7 @@ import org.jclouds.logging.jdk.config.JDKLoggingModule; import com.google.inject.Module; /** - * Creates {@link AzureBlobStoreContext} instances based on the most commonly requested - * arguments. + * Creates {@link AzureBlobStoreContext} instances based on the most commonly requested arguments. *

* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. *

@@ -49,20 +49,19 @@ import com.google.inject.Module; public class AzureBlobStoreContextFactory { public static BlobStoreContext createContext(Properties properties, Module... modules) { - return new AzureBlobStoreContextBuilder(new AzureBlobStorePropertiesBuilder( - properties).build()).withModules(modules).buildContext(); + return new AzureBlobStoreContextBuilder(new AzureBlobPropertiesBuilder(properties).build()) + .withModules(modules).buildContext(); } - public static BlobStoreContext createContext(String user, + public static BlobStoreContext createContext(String user, String encodedKey, + Module... modules) { + return new AzureBlobStoreContextBuilder(new AzureBlobPropertiesBuilder(user, encodedKey) + .build()).withModules(modules).buildContext(); + } + + public static BlobStoreContext createContext(URI endpoint, String user, String encodedKey, Module... modules) { - return new AzureBlobStoreContextBuilder(new AzureBlobStorePropertiesBuilder( - user, encodedKey).build()).withModules(modules).buildContext(); - } - - public static BlobStoreContext createContext(URI endpoint, - String user, String encodedKey, Module... modules) { - return new AzureBlobStoreContextBuilder(new AzureBlobStorePropertiesBuilder( - user, encodedKey).withEndpoint(endpoint).build()).withModules( - modules).buildContext(); + return new AzureBlobStoreContextBuilder(new AzureBlobPropertiesBuilder(user, encodedKey) + .withEndpoint(endpoint).build()).withModules(modules).buildContext(); } } diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStorePropertiesBuilder.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStorePropertiesBuilder.java deleted file mode 100644 index ee97461b23..0000000000 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStorePropertiesBuilder.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * - * Copyright (C) 2009 Cloud Conscious, LLC. - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ -package org.jclouds.azure.storage.blob.blobstore; - -import java.util.Properties; - -import org.jclouds.azure.storage.blob.AzureBlobPropertiesBuilder; -import org.jclouds.blobstore.reference.BlobStoreConstants; - -/** - * Builds properties used in AzureBlob Blob Stores - * - * @author Adrian Cole, Andrew Newdigate - */ -public class AzureBlobStorePropertiesBuilder extends AzureBlobPropertiesBuilder { - - public AzureBlobStorePropertiesBuilder(String id, String secret) { - super(id, secret); - } - - public AzureBlobStorePropertiesBuilder(Properties properties) { - super(properties); - } - - /** - * longest time a single synchronous operation can take before throwing an exception. - */ - public AzureBlobStorePropertiesBuilder withRequestTimeout(long milliseconds) { - properties.setProperty(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT, Long - .toString(milliseconds)); - return this; - } - -} diff --git a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/reference/AzureBlobConstants.java b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/reference/AzureBlobConstants.java index 8cce75a672..db4da32c13 100644 --- a/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/reference/AzureBlobConstants.java +++ b/azure/storage/blob/core/src/main/java/org/jclouds/azure/storage/blob/reference/AzureBlobConstants.java @@ -32,6 +32,24 @@ import org.jclouds.azure.storage.reference.AzureStorageConstants; */ public interface AzureBlobConstants extends AzureStorageConstants { public static final String PROPERTY_AZUREBLOB_ENDPOINT = "jclouds.azureblob.endpoint"; + + /** + * how long do we wait before obtaining a new timestamp for requests. + */ + public static final String PROPERTY_AZUREBLOB_SESSIONINTERVAL = "jclouds.azureblob.sessioninterval"; + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public static final String PROPERTY_AZUREBLOB_TIMEOUT = "jclouds.azureblob.timeout"; + /** + * time to pause before retrying a transient failure + */ + public static final String PROPERTY_AZUREBLOB_RETRY = "jclouds.azureblob.retry"; + /** + * Any header starting with this prefix is considered user metadata. It will be stored with the + * object and returned when you retrieve the object/ + */ public static final String PROPERTY_AZUREBLOB_METADATA_PREFIX = "jclouds.azureblob.metaprefix"; } diff --git a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/AzureBlobContextBuilderTest.java b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/AzureBlobContextBuilderTest.java index e556aab55e..e931b35bae 100644 --- a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/AzureBlobContextBuilderTest.java +++ b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/AzureBlobContextBuilderTest.java @@ -23,7 +23,6 @@ */ package org.jclouds.azure.storage.blob; -import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import static org.testng.Assert.assertEquals; import java.net.URI; @@ -35,6 +34,7 @@ import org.jclouds.azure.storage.blob.config.AzureBlobRestClientModule; import org.jclouds.azure.storage.blob.config.AzureBlobStubClientModule; import org.jclouds.azure.storage.blob.domain.AzureBlob; import org.jclouds.azure.storage.blob.internal.StubAzureBlobClient; +import org.jclouds.azure.storage.blob.reference.AzureBlobConstants; import org.jclouds.azure.storage.reference.AzureStorageConstants; import org.jclouds.blobstore.domain.Blob; import org.jclouds.rest.RestContext; @@ -57,7 +57,8 @@ public class AzureBlobContextBuilderTest { public void testNewBuilder() { AzureBlobContextBuilder builder = new AzureBlobContextBuilder(new AzureBlobPropertiesBuilder( "id", "secret").build()).withModules(new AzureBlobStubClientModule()); - assertEquals(builder.getProperties().getProperty(PROPERTY_USER_METADATA_PREFIX), "x-ms-meta-"); + assertEquals(builder.getProperties().getProperty( + AzureBlobConstants.PROPERTY_AZUREBLOB_METADATA_PREFIX), "x-ms-meta-"); assertEquals(builder.getProperties().getProperty( AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT), "id"); assertEquals(builder.getProperties().getProperty( @@ -65,8 +66,9 @@ public class AzureBlobContextBuilderTest { } public void testBuildContext() { - RestContext context = new AzureBlobContextBuilder(new AzureBlobPropertiesBuilder("id", - "secret").build()).withModules(new AzureBlobStubClientModule()).buildContext(); + RestContext context = new AzureBlobContextBuilder( + new AzureBlobPropertiesBuilder("id", "secret").build()).withModules( + new AzureBlobStubClientModule()).buildContext(); assertEquals(context.getClass(), RestContextImpl.class); assertEquals(context.getApi().getClass(), StubAzureBlobClient.class); assertEquals(context.getAccount(), "id"); @@ -79,7 +81,8 @@ public class AzureBlobContextBuilderTest { assert i.getInstance(Key.get(new TypeLiteral>() { })) != null; assert i.getInstance(AzureBlob.class) != null; - assert i.getInstance(Blob.class) != null; } + assert i.getInstance(Blob.class) != null; + } protected void testAddContextModule() { List modules = new ArrayList(); diff --git a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilderTest.java b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilderTest.java index 1cd599e7c4..79e5051231 100644 --- a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilderTest.java +++ b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/AzureBlobStoreContextBuilderTest.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import org.jclouds.azure.storage.blob.AzureBlobClient; +import org.jclouds.azure.storage.blob.AzureBlobPropertiesBuilder; import org.jclouds.azure.storage.blob.blobstore.config.AzureBlobStoreContextModule; import org.jclouds.azure.storage.blob.config.AzureBlobRestClientModule; import org.jclouds.azure.storage.blob.config.AzureBlobStubClientModule; @@ -68,7 +69,7 @@ public class AzureBlobStoreContextBuilderTest { } private AzureBlobStoreContextBuilder newBuilder() { - return new AzureBlobStoreContextBuilder(new AzureBlobStorePropertiesBuilder("id", + return new AzureBlobStoreContextBuilder(new AzureBlobPropertiesBuilder("id", "secret").build()).withModules(new AzureBlobStubClientModule()); } diff --git a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/integration/AzureBlobTestInitializer.java b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/integration/AzureBlobTestInitializer.java index 76499ada62..6509e62f9a 100644 --- a/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/integration/AzureBlobTestInitializer.java +++ b/azure/storage/blob/core/src/test/java/org/jclouds/azure/storage/blob/blobstore/integration/AzureBlobTestInitializer.java @@ -24,9 +24,9 @@ package org.jclouds.azure.storage.blob.blobstore.integration; import org.jclouds.azure.storage.blob.AzureBlobClient; +import org.jclouds.azure.storage.blob.AzureBlobPropertiesBuilder; import org.jclouds.azure.storage.blob.blobstore.AzureBlobStoreContextBuilder; import org.jclouds.azure.storage.blob.blobstore.AzureBlobStoreContextFactory; -import org.jclouds.azure.storage.blob.blobstore.AzureBlobStorePropertiesBuilder; import org.jclouds.azure.storage.blob.config.AzureBlobStubClientModule; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.integration.internal.BaseTestInitializer; @@ -43,7 +43,7 @@ public class AzureBlobTestInitializer extends BaseTestInitializer createLiveContext(Module configurationModule, String url, String app, String account, String key) { - return new AzureBlobStoreContextBuilder(new AzureBlobStorePropertiesBuilder( + return new AzureBlobStoreContextBuilder(new AzureBlobPropertiesBuilder( account, key).relaxSSLHostname().build()).withModules(configurationModule, new Log4JLoggingModule()).buildContext(); } diff --git a/azure/storage/core/src/main/java/org/jclouds/azure/storage/config/AzureStorageRestClientModule.java b/azure/storage/core/src/main/java/org/jclouds/azure/storage/config/AzureStorageRestClientModule.java index 2493cc25f5..8a1bcfc8f7 100644 --- a/azure/storage/core/src/main/java/org/jclouds/azure/storage/config/AzureStorageRestClientModule.java +++ b/azure/storage/core/src/main/java/org/jclouds/azure/storage/config/AzureStorageRestClientModule.java @@ -25,12 +25,12 @@ package org.jclouds.azure.storage.config; import static org.jclouds.azure.storage.reference.AzureStorageConstants.PROPERTY_AZURESTORAGE_SESSIONINTERVAL; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import javax.inject.Named; import org.jclouds.azure.storage.handlers.ParseAzureStorageErrorFromXmlContent; +import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.RequiresHttp; import org.jclouds.http.annotation.ClientError; @@ -40,8 +40,7 @@ import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.util.DateService; import org.jclouds.util.TimeStamp; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Provides; @@ -56,8 +55,8 @@ public class AzureStorageRestClientModule extends AbstractModule { @Provides @TimeStamp - protected String provideTimeStamp(@TimeStamp ConcurrentMap cache) { - return cache.get("doesn't matter"); + protected String provideTimeStamp(@TimeStamp Supplier cache) { + return cache.get(); } /** @@ -65,15 +64,14 @@ public class AzureStorageRestClientModule extends AbstractModule { */ @Provides @TimeStamp - ConcurrentMap provideTimeStampCache( + Supplier provideTimeStampCache( @Named(PROPERTY_AZURESTORAGE_SESSIONINTERVAL) long seconds, final DateService dateService) { - return new MapMaker().expiration(seconds, TimeUnit.SECONDS).makeComputingMap( - new Function() { - public String apply(String key) { - return dateService.rfc822DateFormat(); - } - }); + return new ExpirableSupplier(new Supplier() { + public String get() { + return dateService.rfc822DateFormat(); + } + }, seconds, TimeUnit.SECONDS); } @Override diff --git a/azure/storage/core/src/test/java/org/jclouds/azure/storage/config/AzureStorageRestClientModuleTest.java b/azure/storage/core/src/test/java/org/jclouds/azure/storage/config/AzureStorageRestClientModuleTest.java index 2376e8c8da..3fa30276d3 100644 --- a/azure/storage/core/src/test/java/org/jclouds/azure/storage/config/AzureStorageRestClientModuleTest.java +++ b/azure/storage/core/src/test/java/org/jclouds/azure/storage/config/AzureStorageRestClientModuleTest.java @@ -29,8 +29,6 @@ import static org.jclouds.azure.storage.reference.AzureStorageConstants.PROPERTY import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; -import java.util.concurrent.ConcurrentMap; - import org.jclouds.azure.storage.handlers.ParseAzureStorageErrorFromXmlContent; import org.jclouds.concurrent.WithinThreadExecutorService; import org.jclouds.concurrent.config.ExecutorServiceModule; @@ -43,6 +41,7 @@ import org.jclouds.util.DateService; import org.jclouds.util.Jsr330; import org.testng.annotations.Test; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -70,13 +69,13 @@ public class AzureStorageRestClientModuleTest { void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException { AzureStorageRestClientModule module = new AzureStorageRestClientModule(); - ConcurrentMap map = module.provideTimeStampCache(1, new DateService()); - String timeStamp = map.get("foo"); + Supplier map = module.provideTimeStampCache(1, new DateService()); + String timeStamp = map.get(); for (int i = 0; i < 10; i++) - map.get("foo"); - assertEquals(timeStamp, map.get("foo")); + map.get(); + assertEquals(timeStamp, map.get()); Thread.sleep(1001); - assertFalse(timeStamp.equals(map.get("foo"))); + assertFalse(timeStamp.equals(map.get())); } @Test diff --git a/blobstore/core/src/main/java/org/jclouds/blobstore/reference/BlobStoreConstants.java b/blobstore/core/src/main/java/org/jclouds/blobstore/reference/BlobStoreConstants.java index 59913fee7c..05f0d84324 100755 --- a/blobstore/core/src/main/java/org/jclouds/blobstore/reference/BlobStoreConstants.java +++ b/blobstore/core/src/main/java/org/jclouds/blobstore/reference/BlobStoreConstants.java @@ -29,6 +29,11 @@ package org.jclouds.blobstore.reference; * @author Adrian Cole */ public interface BlobStoreConstants { + /** + * comma-separated, fully qualified class names of implementations of BlobStoreContextBuilder + * + */ + public static final String PROPERTY_BLOBSTORE_CONTEXTBUILDERS = "jclouds.blobstore.contextbuilders"; /** * longest time a single synchronous operation can take before throwing an exception. diff --git a/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobFromHeadersAndHttpContentTest.java b/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobFromHeadersAndHttpContentTest.java index af98216981..07f84d4c88 100755 --- a/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobFromHeadersAndHttpContentTest.java +++ b/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobFromHeadersAndHttpContentTest.java @@ -79,7 +79,7 @@ public class ParseBlobFromHeadersAndHttpContentTest { metadataParser, blobProvider); Multimap allHeaders = ImmutableMultimap.of("key", "value"); HttpResponse from = new HttpResponse(); - from.setHeaders(allHeaders); + from.getHeaders().putAll(allHeaders); Blob object = blobProvider.create(null); callable.addAllHeadersTo(from, object); assertEquals(object.getAllHeaders().get("key"), Collections.singletonList("value")); diff --git a/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobMetadataFromHeadersTest.java b/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobMetadataFromHeadersTest.java index 6dec73fcf2..26a36d605d 100644 --- a/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobMetadataFromHeadersTest.java +++ b/blobstore/core/src/test/java/org/jclouds/blobstore/functions/ParseBlobMetadataFromHeadersTest.java @@ -142,7 +142,7 @@ public class ParseBlobMetadataFromHeadersTest { public void testAddUserMetadataTo() { Multimap allHeaders = ImmutableMultimap.of("prefix" + "key", "value"); HttpResponse from = new HttpResponse(); - from.setHeaders(allHeaders); + from.getHeaders().putAll(allHeaders); MutableBlobMetadata metadata = blobMetadataProvider.get(); parser.addUserMetadataTo(from, metadata); assertEquals(metadata.getUserMetadata().get("key"), "value"); diff --git a/blobstore/core/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobStoreIntegrationTest.java b/blobstore/core/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobStoreIntegrationTest.java index 78aa7a37cb..8a8bccc776 100644 --- a/blobstore/core/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobStoreIntegrationTest.java +++ b/blobstore/core/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobStoreIntegrationTest.java @@ -82,7 +82,7 @@ public class BaseBlobStoreIntegrationTest { protected static volatile AtomicInteger containerIndex = new AtomicInteger(0); protected volatile BlobStoreContext context; - protected static volatile int containerCount = 20; + protected static volatile int containerCount = 10; public static final String CONTAINER_PREFIX = System.getProperty("user.name") + "-blobstore"; /** * two test groups integration and live. diff --git a/core/src/main/java/org/jclouds/concurrent/ExpirableSupplier.java b/core/src/main/java/org/jclouds/concurrent/ExpirableSupplier.java new file mode 100644 index 0000000000..49feaad2e4 --- /dev/null +++ b/core/src/main/java/org/jclouds/concurrent/ExpirableSupplier.java @@ -0,0 +1,64 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ +package org.jclouds.concurrent; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import com.google.common.base.Supplier; + +/** + * Works in google app engine since it doesn't use threads. + * + * @author Adrian Cole + */ +public class ExpirableSupplier implements Supplier { + private final Supplier supplier; + private final AtomicReference currentValue; + private final AtomicLong trigger; + private final long expirationNanos; + + public ExpirableSupplier(Supplier supplier, long duration, TimeUnit unit) { + this.supplier = supplier; + this.expirationNanos = unit.toNanos(duration); + this.currentValue = new AtomicReference(null); + trigger = new AtomicLong(System.nanoTime() + expirationNanos); + } + + void updateIfExpired() { + V current = currentValue.get(); + if (current == null || trigger.get() - System.nanoTime() <= 0) { + trigger.set(System.nanoTime() + expirationNanos); + // we always want the last one to win. think login session + currentValue.set(supplier.get()); + } + } + + public V get() { + updateIfExpired(); + return currentValue.get(); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/http/HttpMessage.java b/core/src/main/java/org/jclouds/http/HttpMessage.java index 05edd229ae..db759ca6b6 100644 --- a/core/src/main/java/org/jclouds/http/HttpMessage.java +++ b/core/src/main/java/org/jclouds/http/HttpMessage.java @@ -47,13 +47,14 @@ public class HttpMessage { return headers; } - public void setHeaders(Multimap headers) { - this.headers = Multimaps.synchronizedMultimap(headers); - } - + /** + * try to get the value, then try as lowercase. + */ public String getFirstHeaderOrNull(String string) { Collection values = headers.get(string); - return (values != null && values.size() >= 1) ? values.iterator().next() : null; + if (values.size() == 0) + values = headers.get(string.toLowerCase()); + return (values.size() >= 1) ? values.iterator().next() : null; } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/http/HttpRequest.java b/core/src/main/java/org/jclouds/http/HttpRequest.java index 393295ef18..a10e60038a 100644 --- a/core/src/main/java/org/jclouds/http/HttpRequest.java +++ b/core/src/main/java/org/jclouds/http/HttpRequest.java @@ -71,7 +71,7 @@ public class HttpRequest extends HttpMessage implements Request { */ public HttpRequest(String method, URI endPoint, Multimap headers) { this(method, endPoint); - setHeaders(checkNotNull(headers, "headers")); + getHeaders().putAll(checkNotNull(headers, "headers")); } /** @@ -84,7 +84,7 @@ public class HttpRequest extends HttpMessage implements Request { protected HttpRequest(String method, URI endPoint, Multimap headers, @Nullable Object entity) { this(method, endPoint); - setHeaders(checkNotNull(headers, "headers")); + getHeaders().putAll(checkNotNull(headers, "headers")); setEntity(entity); } diff --git a/core/src/main/java/org/jclouds/rest/binders/BindToStringEntity.java b/core/src/main/java/org/jclouds/rest/binders/BindToStringEntity.java index 02c95bb6b2..5e0613fc81 100755 --- a/core/src/main/java/org/jclouds/rest/binders/BindToStringEntity.java +++ b/core/src/main/java/org/jclouds/rest/binders/BindToStringEntity.java @@ -23,6 +23,8 @@ */ package org.jclouds.rest.binders; +import java.util.Collections; + import javax.inject.Singleton; import javax.ws.rs.core.HttpHeaders; @@ -40,7 +42,7 @@ public class BindToStringEntity implements Binder { String stringEntity = entity.toString(); if (request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE) == null) request.getHeaders().put(HttpHeaders.CONTENT_TYPE, "application/unknown"); - request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, stringEntity.getBytes().length + ""); + request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,Collections.singletonList(stringEntity.getBytes().length + "")); request.setEntity(stringEntity); } } diff --git a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java index b3b0a29220..f55f53d3fe 100755 --- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java @@ -354,7 +354,6 @@ public class RestAnnotationProcessor { GeneratedHttpRequest request = new GeneratedHttpRequest(httpMethod, endPoint, this, declaring, method, args); - request.setHeaders(headers); addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method); addFiltersIfAnnotated(method, request); if (stringEntity != null) { @@ -362,6 +361,7 @@ public class RestAnnotationProcessor { if (headers.get(HttpHeaders.CONTENT_TYPE) != null) headers.put(HttpHeaders.CONTENT_TYPE, "application/unknown"); } + request.getHeaders().putAll(headers); decorateRequest(request); return request; } diff --git a/core/src/test/java/org/jclouds/http/BaseJettyTest.java b/core/src/test/java/org/jclouds/http/BaseJettyTest.java index f270a1c52e..1ebdf65dda 100644 --- a/core/src/test/java/org/jclouds/http/BaseJettyTest.java +++ b/core/src/test/java/org/jclouds/http/BaseJettyTest.java @@ -149,7 +149,7 @@ public abstract class BaseJettyTest { } else { handleAction(request, response); } - } else if (request.getHeader("Range") != null) { + } else if (request.getHeader("range") != null) { response.sendError(404, "no content"); } else if (request.getHeader("test") != null) { response.setContentType("text/plain"); diff --git a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnFalseIfContainerNotFound.java b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnFalseIfContainerNotFound.java index 98a1f8f2ba..9cb296724e 100644 --- a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnFalseIfContainerNotFound.java +++ b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnFalseIfContainerNotFound.java @@ -23,6 +23,8 @@ */ package org.jclouds.mezeo.pcs2.functions; +import javax.inject.Singleton; + import org.jclouds.blobstore.ContainerNotFoundException; import com.google.common.base.Function; @@ -31,6 +33,7 @@ import com.google.common.base.Function; * * @author Adrian Cole */ +@Singleton public class ReturnFalseIfContainerNotFound implements Function { public Boolean apply(Exception from) { diff --git a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnTrueIfContainerAlreadyExists.java b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnTrueIfContainerAlreadyExists.java index 3b77ceed3a..d392f3a265 100644 --- a/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnTrueIfContainerAlreadyExists.java +++ b/mezeo/pcs2/core/src/main/java/org/jclouds/mezeo/pcs2/functions/ReturnTrueIfContainerAlreadyExists.java @@ -23,6 +23,8 @@ */ package org.jclouds.mezeo.pcs2.functions; +import javax.inject.Singleton; + import org.jclouds.http.HttpResponseException; import com.google.common.base.Function; @@ -31,6 +33,7 @@ import com.google.common.base.Function; * * @author Adrian Cole */ +@Singleton public class ReturnTrueIfContainerAlreadyExists implements Function { public Boolean apply(Exception from) { diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesPropertiesBuilder.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesPropertiesBuilder.java index 94ce8613ff..adeda01c73 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesPropertiesBuilder.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/CloudFilesPropertiesBuilder.java @@ -23,8 +23,9 @@ */ package org.jclouds.rackspace.cloudfiles; -import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_METADATA_PREFIX; +import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_RETRY; +import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_TIMEOUT; import java.util.Properties; @@ -40,7 +41,6 @@ public class CloudFilesPropertiesBuilder extends RackspacePropertiesBuilder { protected Properties defaultProperties() { Properties properties = super.defaultProperties(); properties.setProperty(PROPERTY_CLOUDFILES_METADATA_PREFIX, "X-Object-Meta-"); - properties.setProperty(PROPERTY_USER_METADATA_PREFIX, "X-Object-Meta-"); return properties; } @@ -52,4 +52,24 @@ public class CloudFilesPropertiesBuilder extends RackspacePropertiesBuilder { super(id, secret); } + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public CloudFilesPropertiesBuilder withRequestTimeout(long milliseconds) { + properties.setProperty(PROPERTY_CLOUDFILES_TIMEOUT, Long.toString(milliseconds)); + return this; + } + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public CloudFilesPropertiesBuilder withMaxRetries(int retries) { + properties.setProperty(PROPERTY_CLOUDFILES_RETRY, Integer.toString(retries)); + return this; + } + + protected CloudFilesPropertiesBuilder withMetaPrefix(String prefix) { + properties.setProperty(PROPERTY_CLOUDFILES_METADATA_PREFIX, prefix); + return this; + } } diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/BindCFObjectToEntity.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/BindCFObjectToEntity.java index 05a479ff4f..a1d62f7307 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/BindCFObjectToEntity.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/binders/BindCFObjectToEntity.java @@ -26,6 +26,7 @@ package org.jclouds.rackspace.cloudfiles.binders; import static com.google.common.base.Preconditions.checkArgument; import javax.inject.Inject; +import javax.inject.Named; import javax.ws.rs.core.HttpHeaders; import org.jclouds.blobstore.binders.BindBlobToEntityAndUserMetadataToHeadersWithPrefix; @@ -33,16 +34,15 @@ import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpUtils; import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlob; import org.jclouds.rackspace.cloudfiles.domain.CFObject; -import org.jclouds.rest.Binder; +import org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants; -public class BindCFObjectToEntity implements Binder { - private final BindBlobToEntityAndUserMetadataToHeadersWithPrefix blobBinder; +public class BindCFObjectToEntity extends BindBlobToEntityAndUserMetadataToHeadersWithPrefix { private final ObjectToBlob object2Blob; @Inject public BindCFObjectToEntity(ObjectToBlob object2Blob, - BindBlobToEntityAndUserMetadataToHeadersWithPrefix blobBinder) { - this.blobBinder = blobBinder; + @Named(CloudFilesConstants.PROPERTY_CLOUDFILES_METADATA_PREFIX) String prefix) { + super(prefix); this.object2Blob = object2Blob; } @@ -57,7 +57,7 @@ public class BindCFObjectToEntity implements Binder { request.getHeaders().put("Transfer-Encoding", "chunked"); } - blobBinder.bindToRequest(request, object2Blob.apply(object)); + super.bindToRequest(request, object2Blob.apply(object)); if (object.getInfo().getHash() != null) { request.getHeaders().put(HttpHeaders.ETAG, HttpUtils.toHexString(object.getInfo().getHash())); diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilder.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilder.java index 25c1eb2565..e52af883e0 100755 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilder.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilder.java @@ -23,8 +23,15 @@ */ package org.jclouds.rackspace.cloudfiles.blobstore; +import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_BLOBSTORE_RETRY; +import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; +import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_METADATA_PREFIX; +import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_RETRY; +import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PROPERTY_CLOUDFILES_TIMEOUT; + import java.util.List; import java.util.Properties; +import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import org.jclouds.blobstore.BlobStoreContextBuilder; @@ -35,13 +42,14 @@ import org.jclouds.rackspace.cloudfiles.blobstore.config.CloudFilesBlobStoreCont import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule; import org.jclouds.rackspace.config.RackspaceAuthenticationRestModule; +import com.google.common.collect.ImmutableMap; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.TypeLiteral; /** - * Creates {@link CloudFilesBlobStoreContext} or {@link Injector} instances based on the most commonly - * requested arguments. + * Creates {@link CloudFilesBlobStoreContext} or {@link Injector} instances based on the most + * commonly requested arguments. *

* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided. *

@@ -56,7 +64,17 @@ public class CloudFilesBlobStoreContextBuilder extends BlobStoreContextBuilder() { - }, props); + }, convert(props)); + } + + private static Properties convert(Properties props) { + for (Entry entry : ImmutableMap.of(PROPERTY_CLOUDFILES_METADATA_PREFIX, + PROPERTY_USER_METADATA_PREFIX, PROPERTY_CLOUDFILES_RETRY, PROPERTY_BLOBSTORE_RETRY, + PROPERTY_CLOUDFILES_TIMEOUT, PROPERTY_USER_METADATA_PREFIX).entrySet()) { + if (props.containsKey(entry.getKey())) + props.setProperty(entry.getValue(), props.getProperty(entry.getKey())); + } + return props; } @Override diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextFactory.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextFactory.java index 6d2143ca0d..b5578846ab 100755 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextFactory.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextFactory.java @@ -30,6 +30,7 @@ import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; import org.jclouds.rackspace.cloudfiles.CloudFilesClient; +import org.jclouds.rackspace.cloudfiles.CloudFilesPropertiesBuilder; import com.google.inject.Module; @@ -49,20 +50,19 @@ import com.google.inject.Module; public class CloudFilesBlobStoreContextFactory { public static BlobStoreContext createContext(Properties properties, Module... modules) { - return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder( - properties).build()).withModules(modules).buildContext(); + return new CloudFilesBlobStoreContextBuilder(new CloudFilesPropertiesBuilder(properties) + .build()).withModules(modules).buildContext(); } - public static BlobStoreContext createContext(String user, + public static BlobStoreContext createContext(String user, String key, + Module... modules) { + return new CloudFilesBlobStoreContextBuilder(new CloudFilesPropertiesBuilder(user, key) + .build()).withModules(modules).buildContext(); + } + + public static BlobStoreContext createContext(URI endpoint, String user, String key, Module... modules) { - return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder( - user, key).build()).withModules(modules).buildContext(); - } - - public static BlobStoreContext createContext(URI endpoint, - String user, String key, Module... modules) { - return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder( - user, key).withEndpoint(endpoint).build()).withModules( - modules).buildContext(); + return new CloudFilesBlobStoreContextBuilder(new CloudFilesPropertiesBuilder(user, key) + .withEndpoint(endpoint).build()).withModules(modules).buildContext(); } } diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStorePropertiesBuilder.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStorePropertiesBuilder.java deleted file mode 100644 index 7231585be5..0000000000 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStorePropertiesBuilder.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * - * Copyright (C) 2009 Cloud Conscious, LLC. - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ -package org.jclouds.rackspace.cloudfiles.blobstore; - -import java.util.Properties; - -import org.jclouds.blobstore.reference.BlobStoreConstants; -import org.jclouds.rackspace.cloudfiles.CloudFilesPropertiesBuilder; - -/** - * Builds properties used in CloudFiles Blob Stores - * - * @author Adrian Cole, Andrew Newdigate - */ -public class CloudFilesBlobStorePropertiesBuilder extends CloudFilesPropertiesBuilder { - - public CloudFilesBlobStorePropertiesBuilder(String id, String secret) { - super(id, secret); - } - - public CloudFilesBlobStorePropertiesBuilder(Properties properties) { - super(properties); - } - - /** - * longest time a single synchronous operation can take before throwing an exception. - */ - public CloudFilesBlobStorePropertiesBuilder withRequestTimeout(long milliseconds) { - properties.setProperty(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT, Long - .toString(milliseconds)); - return this; - } - -} diff --git a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/reference/CloudFilesConstants.java b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/reference/CloudFilesConstants.java index 66c2b2add1..af5338bbf6 100644 --- a/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/reference/CloudFilesConstants.java +++ b/rackspace/cloudfiles/core/src/main/java/org/jclouds/rackspace/cloudfiles/reference/CloudFilesConstants.java @@ -49,7 +49,18 @@ public interface CloudFilesConstants extends RackspaceConstants { * For a string value X, return the Object names nested in the pseudo path. */ String PATH = "path"; - - String PROPERTY_CLOUDFILES_METADATA_PREFIX = "jclouds.cloudfiles.metaprefix"; - + + /** + * longest time a single synchronous operation can take before throwing an exception. + */ + public static final String PROPERTY_CLOUDFILES_TIMEOUT = "jclouds.cloudfiles.timeout"; + /** + * time to pause before retrying a transient failure + */ + public static final String PROPERTY_CLOUDFILES_RETRY = "jclouds.cloudfiles.retry"; + /** + * Any header starting with this prefix is considered user metadata. It will be stored with the + * object and returned when you retrieve the object/ + */ + public static final String PROPERTY_CLOUDFILES_METADATA_PREFIX = "jclouds.cloudfiles.metaprefix"; } diff --git a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilderTest.java b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilderTest.java index 89fda8f42e..f772ca2373 100644 --- a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilderTest.java +++ b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/CloudFilesBlobStoreContextBuilderTest.java @@ -36,6 +36,7 @@ import org.jclouds.blobstore.domain.internal.BlobImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.rackspace.StubRackspaceAuthenticationModule; import org.jclouds.rackspace.cloudfiles.CloudFilesClient; +import org.jclouds.rackspace.cloudfiles.CloudFilesPropertiesBuilder; import org.jclouds.rackspace.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule; import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule; import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule; @@ -69,7 +70,7 @@ public class CloudFilesBlobStoreContextBuilderTest { } private CloudFilesBlobStoreContextBuilder newBuilder() { - return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder("id", + return new CloudFilesBlobStoreContextBuilder(new CloudFilesPropertiesBuilder("id", "secret").build()).withModules(new CloudFilesStubClientModule(), new StubRackspaceAuthenticationModule()); } diff --git a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/integration/CloudFilesTestInitializer.java b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/integration/CloudFilesTestInitializer.java index cb33918c11..52dfae990f 100644 --- a/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/integration/CloudFilesTestInitializer.java +++ b/rackspace/cloudfiles/core/src/test/java/org/jclouds/rackspace/cloudfiles/blobstore/integration/CloudFilesTestInitializer.java @@ -28,9 +28,9 @@ import org.jclouds.blobstore.integration.internal.BaseTestInitializer; import org.jclouds.logging.log4j.config.Log4JLoggingModule; import org.jclouds.rackspace.StubRackspaceAuthenticationModule; import org.jclouds.rackspace.cloudfiles.CloudFilesClient; +import org.jclouds.rackspace.cloudfiles.CloudFilesPropertiesBuilder; import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStoreContextBuilder; import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStoreContextFactory; -import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStorePropertiesBuilder; import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule; import com.google.inject.Module; @@ -44,8 +44,8 @@ public class CloudFilesTestInitializer extends BaseTestInitializer createLiveContext(Module configurationModule, String url, String app, String account, String key) { - return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder( - account, key).relaxSSLHostname().build()).withModules(configurationModule, + return new CloudFilesBlobStoreContextBuilder(new CloudFilesPropertiesBuilder(account, key) + .relaxSSLHostname().build()).withModules(configurationModule, new Log4JLoggingModule()).buildContext(); } diff --git a/rackspace/core/src/main/java/org/jclouds/rackspace/functions/ParseAuthenticationResponseFromHeaders.java b/rackspace/core/src/main/java/org/jclouds/rackspace/functions/ParseAuthenticationResponseFromHeaders.java index de5f5a3ee8..2f71c6d881 100755 --- a/rackspace/core/src/main/java/org/jclouds/rackspace/functions/ParseAuthenticationResponseFromHeaders.java +++ b/rackspace/core/src/main/java/org/jclouds/rackspace/functions/ParseAuthenticationResponseFromHeaders.java @@ -51,32 +51,27 @@ public class ParseAuthenticationResponseFromHeaders implements * parses the http response headers to create a new {@link AuthenticationResponse} object. */ public AuthenticationResponse apply(final HttpResponse from) { - return new AuthenticationResponse() { public String getAuthToken() { - return checkNotNull(from.getFirstHeaderOrNull(AUTH_TOKEN), - AUTH_TOKEN); + return checkNotNull(from.getFirstHeaderOrNull(AUTH_TOKEN), AUTH_TOKEN); } public URI getCDNManagementUrl() { - String cdnManagementUrl = checkNotNull(from - .getFirstHeaderOrNull(CDN_MANAGEMENT_URL), + String cdnManagementUrl = checkNotNull(from.getFirstHeaderOrNull(CDN_MANAGEMENT_URL), CDN_MANAGEMENT_URL); return URI.create(cdnManagementUrl); } public URI getServerManagementUrl() { String serverManagementUrl = checkNotNull(from - .getFirstHeaderOrNull(SERVER_MANAGEMENT_URL), - SERVER_MANAGEMENT_URL); + .getFirstHeaderOrNull(SERVER_MANAGEMENT_URL), SERVER_MANAGEMENT_URL); return URI.create(serverManagementUrl); } - + public URI getStorageUrl() { - String storageUrl = checkNotNull(from - .getFirstHeaderOrNull(STORAGE_URL), - STORAGE_URL); + String storageUrl = checkNotNull(from.getFirstHeaderOrNull(STORAGE_URL), STORAGE_URL + + " not found in headers:" + from.getStatusLine() + " - " + from.getHeaders()); return URI.create(storageUrl); } diff --git a/vcloudx/core/src/main/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModule.java b/vcloudx/core/src/main/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModule.java index bd1fff6fd2..4ffdfc5a87 100755 --- a/vcloudx/core/src/main/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModule.java +++ b/vcloudx/core/src/main/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModule.java @@ -30,29 +30,27 @@ import static org.jclouds.vcloudx.reference.VCloudXConstants.PROPERTY_VCLOUDX_US import java.io.UnsupportedEncodingException; import java.net.URI; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import javax.inject.Named; import javax.inject.Singleton; +import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.http.RequiresHttp; import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.rest.RestClientFactory; -import org.jclouds.vcloudx.VCloudXLogin; import org.jclouds.vcloudx.VCloudToken; +import org.jclouds.vcloudx.VCloudXLogin; import org.jclouds.vcloudx.VCloudXLogin.VCloudXSession; import org.jclouds.vcloudx.endpoints.Org; import org.jclouds.vcloudx.endpoints.VCloudX; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Provides; /** - * Configures the VCloudX authentication service connection, including logging and http - * transport. + * Configures the VCloudX authentication service connection, including logging and http transport. * * @author Adrian Cole */ @@ -65,28 +63,28 @@ public class RestVCloudXAuthenticationModule extends AbstractModule { @VCloudToken @Provides - String provideVCloudToken(ConcurrentMap cache) { - return cache.get("doesn't matter").getVCloudToken(); + String provideVCloudToken(Supplier cache) { + return cache.get().getVCloudToken(); } - + @Provides @Org - protected URI provideOrg(ConcurrentMap cache) { - return cache.get("doesn't matter").getOrg(); + protected URI provideOrg(Supplier cache) { + return cache.get().getOrg(); } /** * borrowing concurrency code to ensure that caching takes place properly */ @Provides - ConcurrentMap provideVCloudTokenCache( + @Singleton + Supplier provideVCloudTokenCache( @Named(PROPERTY_VCLOUDX_SESSIONINTERVAL) long seconds, final VCloudXLogin login) { - return new MapMaker().expiration(seconds, TimeUnit.SECONDS).makeComputingMap( - new Function() { - public VCloudXSession apply(String key) { - return login.login(); - } - }); + return new ExpirableSupplier(new Supplier() { + public VCloudXSession get() { + return login.login(); + } + }, seconds, TimeUnit.SECONDS); } @Provides diff --git a/vcloudx/core/src/test/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModuleTest.java b/vcloudx/core/src/test/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModuleTest.java index 0388c235a4..712f68ca44 100644 --- a/vcloudx/core/src/test/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModuleTest.java +++ b/vcloudx/core/src/test/java/org/jclouds/vcloudx/config/RestVCloudXAuthenticationModuleTest.java @@ -30,7 +30,6 @@ import static org.jclouds.vcloudx.reference.VCloudXConstants.PROPERTY_VCLOUDX_US import static org.testng.Assert.assertEquals; import java.net.URI; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import org.jclouds.http.HttpRetryHandler; @@ -44,6 +43,7 @@ import org.jclouds.vcloudx.VCloudXLogin; import org.jclouds.vcloudx.VCloudXLogin.VCloudXSession; import org.testng.annotations.Test; +import com.google.common.base.Supplier; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -91,12 +91,12 @@ public class RestVCloudXAuthenticationModuleTest { } }; - ConcurrentMap map = module.provideVCloudTokenCache(1, login); + Supplier map = module.provideVCloudTokenCache(1, login); for (int i = 0; i < 10; i++) - map.get("foo"); - assert "1".equals(map.get("foo").getVCloudToken()); + map.get(); + assert "1".equals(map.get().getVCloudToken()); Thread.sleep(1001); - assert "2".equals(map.get("foo").getVCloudToken()); + assert "2".equals(map.get().getVCloudToken()); } @Test