From bdd739ad04993ec30d1b31c18833efec590e5c4f Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Thu, 2 Feb 2012 07:22:46 -0800 Subject: [PATCH] Issue 826:support api-generated location metadata across service types, note this ensures authenticationexceptions propagate even after context creation --- .../BYONComputeServiceContextModule.java | 10 +- .../internal/BYONComputeServiceAdapter.java | 2 +- .../TransientBlobStoreContextModule.java | 2 - .../BaseComputeServiceContextModule.java | 22 +- .../config/BindComputeSuppliersByClass.java | 43 +-- .../ComputeServiceAdapterContextModule.java | 55 ++-- .../config/StubComputeServiceAdapter.java | 2 +- .../StubComputeServiceContextModule.java | 6 - .../jclouds/concurrent/FutureIterables.java | 28 +- .../TransformParallelException.java | 61 +++++ .../java/org/jclouds/functions/JoinOnK2.java | 48 ++++ .../location/config/LocationModule.java | 127 +++++++-- .../ProvideRegionToURIViaProperties.java | 81 ------ .../config/ProvideZonesViaProperties.java | 77 ------ .../RegionToEndpointOrProviderIfNull.java | 16 +- .../location/functions/ZoneToEndpoint.java | 18 +- .../predicates/LocationPredicates.java | 18 ++ .../ImplicitLocationSupplier.java} | 31 +-- .../suppliers/ImplicitRegionIdSupplier.java | 33 +++ .../LocationIdToIso3166CodesSupplier.java | 38 +++ .../LocationsSupplier.java} | 20 +- .../suppliers/ProviderURISupplier.java | 31 +++ .../suppliers/RegionIdToURISupplier.java | 37 +++ .../suppliers/RegionIdToZoneIdsSupplier.java | 36 +++ .../location/suppliers/RegionIdsSupplier.java | 35 +++ .../suppliers/ZoneIdToURISupplier.java | 37 +++ .../location/suppliers/ZoneIdsSupplier.java | 35 +++ .../ZoneToRegionToProviderOrJustProvider.java | 89 ------- .../suppliers/{ => all}/JustProvider.java | 14 +- .../RegionToProviderOrJustProvider.java | 36 ++- .../ZoneToRegionToProviderOrJustProvider.java | 142 ++++++++++ ...ionIdToIso3166CodesFromConfiguration.java} | 26 +- ...IFromConfigurationOrDefaultToProvider.java | 78 ++++++ .../ProviderURIFromConfiguration.java | 39 +++ ...IFromConfigurationOrDefaultToProvider.java | 51 ++++ .../RegionIdToZoneIdsFromConfiguration.java | 91 +++++++ .../RegionIdsFromConfiguration.java | 45 ++++ .../fromconfig/SplitConfigurationKey.java | 63 +++++ ...IFromConfigurationOrDefaultToProvider.java | 51 ++++ .../fromconfig/ZoneIdsFromConfiguration.java | 45 ++++ .../GetRegionIdMatchingProviderURIOrNull.java | 44 ++++ ...FirstRegionOptionallyMatchingRegionId.java | 19 +- .../OnlyLocationOrFirstZone.java | 5 +- .../org/jclouds/rest/RestContextBuilder.java | 145 +--------- .../config/BindPropertiesToAnnotations.java | 168 ++++++++++++ .../jclouds/rest/config/RestClientModule.java | 21 +- .../internal/RestAnnotationProcessor.java | 24 +- ...utNotOnAuthorizationExceptionSupplier.java | 5 + .../rest/suppliers/URIFromStringSupplier.java | 43 +++ .../SupplyKeyMatchingValueOrNull.java | 64 +++++ .../src/main/java/org/jclouds/util/Maps2.java | 13 + .../java/org/jclouds/util/Suppliers2.java | 32 ++- .../java/org/jclouds/util/Throwables2.java | 38 ++- .../FutureIterablesPerformanceTest.java | 249 ++++++++++++++++++ .../concurrent/FutureIterablesTest.java | 232 +++------------- ...166CodesByLocationIdViaPropertiesTest.java | 21 +- .../RegionToEndpointOrProviderIfNullTest.java | 22 +- .../functions/ZoneToEndpointTest.java | 20 +- .../suppliers/{ => all}/JustProviderTest.java | 3 +- ...tRegionOptionallyMatchingRegionIdTest.java | 30 +-- .../OnlyLocationOrFirstZoneTest.java | 3 +- .../internal/RestAnnotationProcessorTest.java | 10 +- .../org/jclouds/util/Throwables2Test.java | 36 +++ .../BaseLoadBalancerServiceContextModule.java | 32 --- .../BindLoadBalancerSuppliersByClass.java | 92 ------- ...verManagerComputeServiceContextModule.java | 6 +- 66 files changed, 2081 insertions(+), 1015 deletions(-) create mode 100644 core/src/main/java/org/jclouds/concurrent/TransformParallelException.java create mode 100644 core/src/main/java/org/jclouds/functions/JoinOnK2.java delete mode 100644 core/src/main/java/org/jclouds/location/config/ProvideRegionToURIViaProperties.java delete mode 100644 core/src/main/java/org/jclouds/location/config/ProvideZonesViaProperties.java rename core/src/main/java/org/jclouds/location/{config/JustProviderLocationModule.java => suppliers/ImplicitLocationSupplier.java} (54%) create mode 100644 core/src/main/java/org/jclouds/location/suppliers/ImplicitRegionIdSupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/LocationIdToIso3166CodesSupplier.java rename core/src/main/java/org/jclouds/location/{config/RegionsLocationModule.java => suppliers/LocationsSupplier.java} (60%) create mode 100644 core/src/main/java/org/jclouds/location/suppliers/ProviderURISupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/RegionIdToURISupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/RegionIdToZoneIdsSupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/RegionIdsSupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/ZoneIdToURISupplier.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/ZoneIdsSupplier.java delete mode 100644 core/src/main/java/org/jclouds/location/suppliers/ZoneToRegionToProviderOrJustProvider.java rename core/src/main/java/org/jclouds/location/suppliers/{ => all}/JustProvider.java (79%) rename core/src/main/java/org/jclouds/location/suppliers/{ => all}/RegionToProviderOrJustProvider.java (61%) create mode 100644 core/src/main/java/org/jclouds/location/suppliers/all/ZoneToRegionToProviderOrJustProvider.java rename core/src/main/java/org/jclouds/location/{config/ProvideIso3166CodesByLocationIdViaProperties.java => suppliers/fromconfig/LocationIdToIso3166CodesFromConfiguration.java} (73%) create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToURIFromConfigurationOrDefaultToProvider.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/ProviderURIFromConfiguration.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToURIFromConfigurationOrDefaultToProvider.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToZoneIdsFromConfiguration.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdsFromConfiguration.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/SplitConfigurationKey.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdToURIFromConfigurationOrDefaultToProvider.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdsFromConfiguration.java create mode 100644 core/src/main/java/org/jclouds/location/suppliers/implicit/GetRegionIdMatchingProviderURIOrNull.java rename core/src/main/java/org/jclouds/location/suppliers/{ => implicit}/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java (79%) rename core/src/main/java/org/jclouds/location/suppliers/{ => implicit}/OnlyLocationOrFirstZone.java (92%) create mode 100644 core/src/main/java/org/jclouds/rest/config/BindPropertiesToAnnotations.java create mode 100644 core/src/main/java/org/jclouds/rest/suppliers/URIFromStringSupplier.java create mode 100644 core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java create mode 100644 core/src/test/java/org/jclouds/concurrent/FutureIterablesPerformanceTest.java rename core/src/test/java/org/jclouds/location/suppliers/{ => all}/JustProviderTest.java (94%) rename core/src/test/java/org/jclouds/location/suppliers/{ => implicit}/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java (79%) rename core/src/test/java/org/jclouds/location/suppliers/{ => implicit}/OnlyLocationOrFirstZoneTest.java (96%) delete mode 100644 loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BindLoadBalancerSuppliersByClass.java diff --git a/apis/byon/src/main/java/org/jclouds/byon/config/BYONComputeServiceContextModule.java b/apis/byon/src/main/java/org/jclouds/byon/config/BYONComputeServiceContextModule.java index fc1707c043..f00b3db1e7 100644 --- a/apis/byon/src/main/java/org/jclouds/byon/config/BYONComputeServiceContextModule.java +++ b/apis/byon/src/main/java/org/jclouds/byon/config/BYONComputeServiceContextModule.java @@ -27,10 +27,12 @@ import org.jclouds.byon.Node; import org.jclouds.byon.internal.BYONComputeServiceAdapter; import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty; import org.jclouds.compute.config.JCloudsNativeComputeServiceAdapterContextModule; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.concurrent.SingleThreaded; import org.jclouds.domain.Location; import org.jclouds.location.Provider; -import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; import com.google.common.base.Function; import com.google.common.base.Supplier; @@ -45,7 +47,7 @@ import com.google.inject.TypeLiteral; @SuppressWarnings("unchecked") @SingleThreaded public class BYONComputeServiceContextModule extends - JCloudsNativeComputeServiceAdapterContextModule { + JCloudsNativeComputeServiceAdapterContextModule { public BYONComputeServiceContextModule() { super(Supplier.class, Supplier.class, BYONComputeServiceAdapter.class); @@ -60,14 +62,12 @@ public class BYONComputeServiceContextModule extends @Override protected void configure() { super.configure(); - bind(new TypeLiteral>() { - }).to(OnlyLocationOrFirstZone.class); bind(new TypeLiteral>() { }).to(SupplyFromProviderURIOrNodesProperty.class); bind(new TypeLiteral>() { }).annotatedWith(Provider.class).to(SupplyFromProviderURIOrNodesProperty.class); bind(new TypeLiteral>() { }).to(SupplyFromProviderURIOrNodesProperty.class); + install(new LocationsFromComputeServiceAdapterModule(){}); } - } diff --git a/apis/byon/src/main/java/org/jclouds/byon/internal/BYONComputeServiceAdapter.java b/apis/byon/src/main/java/org/jclouds/byon/internal/BYONComputeServiceAdapter.java index 5a8d676804..6ae9ecdd4a 100644 --- a/apis/byon/src/main/java/org/jclouds/byon/internal/BYONComputeServiceAdapter.java +++ b/apis/byon/src/main/java/org/jclouds/byon/internal/BYONComputeServiceAdapter.java @@ -35,7 +35,7 @@ import org.jclouds.compute.domain.Template; import org.jclouds.domain.Location; import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationScope; -import org.jclouds.location.suppliers.JustProvider; +import org.jclouds.location.suppliers.all.JustProvider; import com.google.common.base.Function; import com.google.common.base.Predicates; diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java index 31dd22de75..001db97086 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java @@ -31,7 +31,6 @@ import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.domain.Location; -import org.jclouds.location.config.JustProviderLocationModule; import com.google.inject.AbstractModule; import com.google.inject.Scopes; @@ -59,7 +58,6 @@ public class TransientBlobStoreContextModule extends AbstractModule { }).toInstance(containerToLocation); install(new BlobStoreObjectModule()); install(new BlobStoreMapModule()); - install(new JustProviderLocationModule()); bind(BlobStore.class).to(TransientBlobStore.class); bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT); bind(BlobRequestSigner.class).to(TransientBlobRequestSigner.class); diff --git a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java index 1c3cbbc868..ce6863e6e9 100644 --- a/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/BaseComputeServiceContextModule.java @@ -55,7 +55,6 @@ import org.jclouds.config.ValueOfConfigurationKeyOrNull; import org.jclouds.domain.LoginCredentials; import org.jclouds.json.Json; import org.jclouds.location.Provider; -import org.jclouds.location.config.LocationModule; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; import org.jclouds.scriptbuilder.domain.Statement; @@ -81,7 +80,6 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { @Override protected void configure() { - configureLocationModule(); install(new ComputeServiceTimeoutsModule()); bind(new TypeLiteral>() { }).to(CreateSshClientOncePortIsListeningOnNode.class); @@ -115,10 +113,6 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { install(new FactoryModuleBuilder().build(BlockUntilInitScriptStatusIsZeroThenReturnOutput.Factory.class)); } - protected void configureLocationModule() { - install(new LocationModule(authException)); - } - @Singleton static class RunScriptOnNodeFactoryImpl implements RunScriptOnNode.Factory { @@ -210,8 +204,6 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { return "%s-%s"; } - protected AtomicReference authException = new AtomicReference(); - @Provides @Singleton protected Supplier> provideImageMap(@Memoized Supplier> images) { @@ -235,12 +227,12 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { @Provides @Singleton @Memoized - protected Supplier> supplyImageCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + protected Supplier> supplyImageCache(AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, final Supplier> imageSupplier, Injector injector) { if (shouldParseImagesOnDemand(injector)) { - return supplyImageCache(seconds, imageSupplier); + return supplyImageCache(authException, seconds, imageSupplier); } else { - return supplyNonParsingImageCache(seconds, imageSupplier, injector); + return supplyNonParsingImageCache(authException, seconds, imageSupplier, injector); } } @@ -248,7 +240,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { return true; } - protected Supplier> supplyImageCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + protected Supplier> supplyImageCache(AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, final Supplier> imageSupplier) { return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, seconds, new Supplier>() { @@ -262,9 +254,9 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { /** * For overriding; default impl is same as {@link supplyImageCache(seconds, imageSupplier)} */ - protected Supplier> supplyNonParsingImageCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + protected Supplier> supplyNonParsingImageCache(AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, final Supplier> imageSupplier, Injector injector) { - return supplyImageCache(seconds, imageSupplier); + return supplyImageCache(authException, seconds, imageSupplier); } @Provides @@ -290,7 +282,7 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule { @Provides @Singleton @Memoized - protected Supplier> supplySizeCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, + protected Supplier> supplySizeCache(AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, final Supplier> hardwareSupplier) { return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, seconds, new Supplier>() { diff --git a/compute/src/main/java/org/jclouds/compute/config/BindComputeSuppliersByClass.java b/compute/src/main/java/org/jclouds/compute/config/BindComputeSuppliersByClass.java index e8f2bd2b0e..efabd12038 100644 --- a/compute/src/main/java/org/jclouds/compute/config/BindComputeSuppliersByClass.java +++ b/compute/src/main/java/org/jclouds/compute/config/BindComputeSuppliersByClass.java @@ -20,13 +20,8 @@ package org.jclouds.compute.config; import java.util.Set; -import javax.inject.Inject; -import javax.inject.Singleton; - import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Image; -import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; import com.google.common.base.Supplier; import com.google.inject.AbstractModule; @@ -41,54 +36,18 @@ public abstract class BindComputeSuppliersByClass extends AbstractModule { @Override protected void configure() { bindImageSupplier(defineImageSupplier()); - bindLocationSupplier(defineLocationSupplier()); bindHardwareSupplier(defineHardwareSupplier()); - bindDefaultLocationSupplier(defineDefaultLocationSupplier()); } protected abstract Class>> defineImageSupplier(); protected abstract Class>> defineHardwareSupplier(); - protected Class>> defineLocationSupplier() { - return SupplierOfLocationSet.class; - } - - @Singleton - static class SupplierOfLocationSet implements Supplier> { - private final Set locations; - - @Inject - SupplierOfLocationSet(Set locations) { - this.locations = locations; - } - - @Override - public Set get() { - return locations; - } - - } - - protected Class> defineDefaultLocationSupplier() { - return OnlyLocationOrFirstZone.class; - } - protected void bindImageSupplier(Class>> clazz) { bind(new TypeLiteral>>() { }).to(clazz).in(Scopes.SINGLETON); } - - protected void bindLocationSupplier(Class>> clazz) { - bind(new TypeLiteral>>() { - }).to(clazz).in(Scopes.SINGLETON); - } - - protected void bindDefaultLocationSupplier(Class> clazz) { - bind(new TypeLiteral>() { - }).to(clazz).in(Scopes.SINGLETON); - } - + protected void bindHardwareSupplier(Class>> clazz) { bind(new TypeLiteral>>() { }).to(clazz).in(Scopes.SINGLETON); diff --git a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java index 8321e094c4..f478be5af8 100644 --- a/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/config/ComputeServiceAdapterContextModule.java @@ -23,15 +23,12 @@ import static com.google.common.base.Predicates.notNull; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; import static com.google.inject.util.Types.newParameterizedType; -import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import java.util.Set; import javax.inject.Inject; -import javax.inject.Named; import javax.inject.Singleton; -import org.jclouds.collect.Memoized; import org.jclouds.collect.TransformingSetSupplier; import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceContext; @@ -50,11 +47,12 @@ import org.jclouds.compute.strategy.SuspendNodeStrategy; import org.jclouds.compute.strategy.impl.AdaptingComputeServiceStrategies; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; -import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; +import org.jclouds.location.suppliers.LocationsSupplier; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; +import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; @@ -82,25 +80,38 @@ public class ComputeServiceAdapterContextModule extends BaseCo (TypeLiteral) TypeLiteral.get(newParameterizedType(ComputeServiceContextImpl.class, syncClientType, asyncClientType))).in(Scopes.SINGLETON); } + + /** + * install this, if you want to use your computeservice adapter to handle locations. Note that if + * you do this, you'll want to instantiate a subclass to prevent type erasure. + * + * ex. + *
+    *       install(new LocationsFromComputeServiceAdapterModule(){});
+    * 
+ * not + *
+    *       install(new LocationsFromComputeServiceAdapterModule());
+    * 
+ */ + public static class LocationsFromComputeServiceAdapterModule extends AbstractModule { - @Override - protected void configureLocationModule() { - // configuring below - } + @Override + protected void configure() { + } - @Provides - @Singleton - @Memoized - protected Supplier> supplyLocationCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, - final ComputeServiceAdapter adapter, final Function transformer) { - return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, - seconds, new Supplier>() { - @Override - public Set get() { - return ImmutableSet. copyOf(transform(filter(adapter.listLocations(), notNull()), - transformer)); - } - }); + @Provides + @Singleton + protected LocationsSupplier supplyLocationsFromComputeServiceAdapter( + final ComputeServiceAdapter adapter, final Function transformer) { + return new LocationsSupplier() { + @Override + public Set get() { + Iterable locations = filter(adapter.listLocations(), notNull()); + return ImmutableSet. copyOf(transform(locations, transformer)); + } + }; + } } @Provides @@ -111,7 +122,7 @@ public class ComputeServiceAdapterContextModule extends BaseCo @Override public Iterable get() { - return filter(adapter.listHardwareProfiles(), notNull()); + return adapter.listHardwareProfiles(); } }, transformer); diff --git a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java index aec50ad3b1..f666b4add2 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java +++ b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceAdapter.java @@ -42,7 +42,7 @@ import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.Template; import org.jclouds.domain.Location; import org.jclouds.domain.LoginCredentials; -import org.jclouds.location.suppliers.JustProvider; +import org.jclouds.location.suppliers.all.JustProvider; import org.jclouds.rest.ResourceNotFoundException; import com.google.common.base.Supplier; diff --git a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceContextModule.java b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceContextModule.java index 2e568810ce..50e80faefc 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceContextModule.java +++ b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceContextModule.java @@ -25,12 +25,8 @@ import javax.inject.Singleton; import org.jclouds.compute.config.JCloudsNativeComputeServiceAdapterContextModule; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.concurrent.SingleThreaded; -import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; -import com.google.common.base.Supplier; import com.google.inject.Provides; -import com.google.inject.TypeLiteral; /** * @@ -54,8 +50,6 @@ public class StubComputeServiceContextModule extends @Override protected void configure() { install(new StubComputeServiceDependenciesModule()); - bind(new TypeLiteral>() { - }).to(OnlyLocationOrFirstZone.class); super.configure(); } } diff --git a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java index 7392deac4d..97bff69ba7 100644 --- a/core/src/main/java/org/jclouds/concurrent/FutureIterables.java +++ b/core/src/main/java/org/jclouds/concurrent/FutureIterables.java @@ -18,7 +18,12 @@ */ package org.jclouds.concurrent; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.collect.Iterables.any; +import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Maps.newHashMap; +import static org.jclouds.util.Throwables2.containsThrowable; +import static org.jclouds.util.Throwables2.propagateAuthorizationOrOriginalException; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -29,20 +34,18 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; -import org.jclouds.javax.annotation.Nullable; import javax.annotation.Resource; import javax.inject.Named; import org.jclouds.Constants; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; import com.google.common.annotations.Beta; import com.google.common.base.Function; -import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; import com.google.inject.Inject; /** @@ -82,6 +85,7 @@ public class FutureIterables { return transformParallel(fromIterable, function, exec, maxTime, logger, logPrefix, retryHandler, maxRetries); } + @SuppressWarnings("unchecked") public static Iterable transformParallel(Iterable fromIterable, Function> function, ExecutorService exec, @Nullable Long maxTime, Logger logger, String logPrefix, BackoffLimitedRetryHandler retryHandler, int maxRetries) { @@ -93,7 +97,7 @@ public class FutureIterables { responses.put(from, function.apply(from)); } exceptions = awaitCompletion(responses, exec, maxTime, logger, logPrefix); - if (exceptions.size() > 0) { + if (exceptions.size() > 0 && !any(exceptions.values(), containsThrowable(AuthorizationException.class))) { fromIterable = exceptions.keySet(); retryHandler.imposeBackoffExponentialDelay(delayStart, 2, i + 1, maxRetries, String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions)); @@ -101,8 +105,10 @@ public class FutureIterables { break; } } + //make sure we propagate any authorization exception so that we don't lock out accounts if (exceptions.size() > 0) - throw new RuntimeException(String.format("error %s: %s: %s", logPrefix, fromIterable, exceptions)); + return propagateAuthorizationOrOriginalException(new TransformParallelException((Map) responses, exceptions, + logPrefix)); return unwrap(responses.values()); } @@ -116,7 +122,7 @@ public class FutureIterables { final AtomicInteger complete = new AtomicInteger(0); final AtomicInteger errors = new AtomicInteger(0); final long start = System.currentTimeMillis(); - final Map errorMap = Maps.newHashMap(); + final Map errorMap = newHashMap(); for (final java.util.Map.Entry> future : responses.entrySet()) { Futures.makeListenable(future.getValue(), exec).addListener(new Runnable() { @@ -157,21 +163,21 @@ public class FutureIterables { String message = message(logPrefix, total, complete.get(), errors.get(), start); TimeoutException exception = new TimeoutException(message); logger.error(exception, message); - Throwables.propagate(exception); + propagate(exception); } return errorMap; } public static Iterable unwrap(Iterable> values) { - return Iterables.transform(values, new Function, T>() { + return transform(values, new Function, T>() { @Override public T apply(Future from) { try { return from.get(); } catch (InterruptedException e) { - Throwables.propagate(e); + propagate(e); } catch (ExecutionException e) { - Throwables.propagate(e); + propagate(e); } return null; } diff --git a/core/src/main/java/org/jclouds/concurrent/TransformParallelException.java b/core/src/main/java/org/jclouds/concurrent/TransformParallelException.java new file mode 100644 index 0000000000..60b2c39445 --- /dev/null +++ b/core/src/main/java/org/jclouds/concurrent/TransformParallelException.java @@ -0,0 +1,61 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.concurrent; + +import java.util.Map; +import java.util.concurrent.Future; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +/** + * A failure occurred while concurrently operating on an Iterable + * + * @author Adrian Cole + */ +public final class TransformParallelException extends RuntimeException { + + /** The serialVersionUID */ + private static final long serialVersionUID = 1L; + + private final Map> success; + private final Map exceptions; + + public TransformParallelException(Map> success, Map exceptions, String messagePrefix) { + super(String.format("error %s: %s", messagePrefix, exceptions)); + this.success = ImmutableMap.copyOf(success); + this.exceptions = ImmutableMap.copyOf(exceptions); + initCause(Iterables.get(exceptions.values(), 0)); + } + + /** + * @return Elements that performed the transform without error + */ + public Map> getSuccessfulToValue() { + return success; + } + + /** + * @return Elements that failed during the transform + */ + public Map getFromToException() { + return exceptions; + } + +} diff --git a/core/src/main/java/org/jclouds/functions/JoinOnK2.java b/core/src/main/java/org/jclouds/functions/JoinOnK2.java new file mode 100644 index 0000000000..39817511c4 --- /dev/null +++ b/core/src/main/java/org/jclouds/functions/JoinOnK2.java @@ -0,0 +1,48 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.functions; + +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; + +public class JoinOnK2 implements Function>>, Map>> { + private final Supplier>> regionToEndpointSupplier; + + public JoinOnK2(Supplier>> regionToEndpointSupplier) { + this.regionToEndpointSupplier = regionToEndpointSupplier; + } + + @Override + public Map> apply(Map>> regionToZones) { + Map> regionToEndpoint = regionToEndpointSupplier.get(); + Builder> builder = ImmutableMap.> builder(); + for (Entry>> entry : regionToZones.entrySet()) { + for (K2 zone : entry.getValue().get()) { + builder.put(zone, regionToEndpoint.get(entry.getKey())); + } + } + return builder.build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/config/LocationModule.java b/core/src/main/java/org/jclouds/location/config/LocationModule.java index 8465d76ee7..640c872452 100644 --- a/core/src/main/java/org/jclouds/location/config/LocationModule.java +++ b/core/src/main/java/org/jclouds/location/config/LocationModule.java @@ -20,6 +20,8 @@ package org.jclouds.location.config; import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import java.net.URI; +import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -28,6 +30,20 @@ import javax.inject.Singleton; import org.jclouds.collect.Memoized; import org.jclouds.domain.Location; +import org.jclouds.location.Iso3166; +import org.jclouds.location.Provider; +import org.jclouds.location.Region; +import org.jclouds.location.Zone; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; +import org.jclouds.location.suppliers.ImplicitRegionIdSupplier; +import org.jclouds.location.suppliers.LocationIdToIso3166CodesSupplier; +import org.jclouds.location.suppliers.LocationsSupplier; +import org.jclouds.location.suppliers.ProviderURISupplier; +import org.jclouds.location.suppliers.RegionIdToURISupplier; +import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; +import org.jclouds.location.suppliers.RegionIdsSupplier; +import org.jclouds.location.suppliers.ZoneIdToURISupplier; +import org.jclouds.location.suppliers.ZoneIdsSupplier; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; @@ -36,35 +52,100 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; /** + * All of these are memoized as locations do not change often at runtime. Note that we take care to + * propagate authorization exceptions. this is so that we do not lock out the account. * * @author Adrian Cole */ public class LocationModule extends AbstractModule { - protected final AtomicReference authException; - - public LocationModule() { - this(new AtomicReference()); - } - - public LocationModule(AtomicReference authException) { - this.authException = authException; - } - - @Provides - @Singleton - @Memoized - protected Supplier> supplyLocationCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, - final Supplier> locationSupplier) { - return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, seconds, - new Supplier>() { - @Override - public Set get() { - return locationSupplier.get(); - } - }); - } @Override protected void configure() { } + + @Provides + @Singleton + @Iso3166 + protected Supplier>>> isoCodesSupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + LocationIdToIso3166CodesSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Provider + protected Supplier provideProvider(AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds, ProviderURISupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + protected Supplier implicitLocationSupplier(AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds, ImplicitLocationSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + // TODO: we should eventually get rid of memoized as an annotation, as it is confusing + @Memoized + protected Supplier> memoizedLocationsSupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + LocationsSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Region + protected Supplier> regionIdsSupplier(AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds, RegionIdsSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Region + protected Supplier>> regionIdToURISupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + RegionIdToURISupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Region + protected Supplier implicitRegionIdSupplier(AtomicReference authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds, ImplicitRegionIdSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Zone + protected Supplier> regionIdsSupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + ZoneIdsSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Zone + protected Supplier>>> regionIdToZoneIdsSupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + RegionIdToZoneIdsSupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } + + @Provides + @Singleton + @Zone + protected Supplier>> zoneIdToURISupplier( + AtomicReference authException, @Named(PROPERTY_SESSION_INTERVAL) long seconds, + ZoneIdToURISupplier uncached) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException, seconds, uncached); + } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/config/ProvideRegionToURIViaProperties.java b/core/src/main/java/org/jclouds/location/config/ProvideRegionToURIViaProperties.java deleted file mode 100644 index 93cd5a6ede..0000000000 --- a/core/src/main/java/org/jclouds/location/config/ProvideRegionToURIViaProperties.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.location.config; - -import static org.jclouds.location.reference.LocationConstants.ENDPOINT; -import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION; -import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; - -import java.net.URI; -import java.util.Map; - -import javax.annotation.Resource; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.location.Region; -import org.jclouds.logging.Logger; - -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; -import com.google.inject.ConfigurationException; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.name.Names; - -/** - * - * looks for properties bound to the naming convention jclouds.region.{@code regionId}.endpoint - * - * @author Adrian Cole - */ -@Singleton -public class ProvideRegionToURIViaProperties implements javax.inject.Provider> { - - private final Injector injector; - - @Resource - protected Logger logger = Logger.NULL; - - @Inject - protected ProvideRegionToURIViaProperties(Injector injector) { - this.injector = injector; - } - - @Singleton - @Region - @Override - public Map get() { - try { - String regionString = injector.getInstance(Key.get(String.class, Names.named(PROPERTY_REGIONS))); - Builder regions = ImmutableMap. builder(); - for (String region : Splitter.on(',').split(regionString)) { - String regionUri = injector.getInstance(Key.get(String.class, Names.named(PROPERTY_REGION + "." + region - + "." + ENDPOINT))); - regions.put(region, URI.create(regionUri)); - } - return regions.build(); - } catch (ConfigurationException e) { - logger.warn("no region name to endpoint mappings configured!"); - return ImmutableMap.of(); - } - } - -} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/config/ProvideZonesViaProperties.java b/core/src/main/java/org/jclouds/location/config/ProvideZonesViaProperties.java deleted file mode 100644 index cb2d3bf6ab..0000000000 --- a/core/src/main/java/org/jclouds/location/config/ProvideZonesViaProperties.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.location.config; - -import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION; - -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.location.Region; -import org.jclouds.location.Zone; - -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; -import com.google.inject.ConfigurationException; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.name.Names; - -/** - * - * looks for properties bound to the naming convention jclouds.location.region.{@code regionId}.zones - * - * @author Adrian Cole - */ -@Singleton -public class ProvideZonesViaProperties implements javax.inject.Provider> { - - private final Injector injector; - private final Set regions; - - @Inject - ProvideZonesViaProperties(Injector injector, @Region Set regions) { - this.injector = injector; - this.regions = regions; - } - - @Singleton - @Zone - @Override - public Map get() { - try { - Builder zones = ImmutableMap. builder(); - for (String region : regions) { - for (String zone : Splitter.on(',').split( - injector.getInstance(Key.get(String.class, Names.named(PROPERTY_REGION + "." + region + ".zones"))))) { - zones.put(zone, region); - } - } - return zones.build(); - } catch (ConfigurationException e) { - // this happens if regions property isn't set - // services not run by AWS may not have zones, so this is ok. - return ImmutableMap. of(); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNull.java b/core/src/main/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNull.java index fc4afa1ca1..52942bbad4 100644 --- a/core/src/main/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNull.java +++ b/core/src/main/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNull.java @@ -32,6 +32,7 @@ import org.jclouds.location.Provider; import org.jclouds.location.Region; import com.google.common.base.Function; +import com.google.common.base.Supplier; /** * Return a uri corresponding to the name of the region (passed argument). @@ -41,25 +42,26 @@ import com.google.common.base.Function; */ @Singleton public class RegionToEndpointOrProviderIfNull implements Function { - private final URI defaultUri; + private final Supplier defaultUri; private final String defaultProvider; - private final Map regionToEndpoint; + private final Supplier>> regionToEndpointSupplier; @Inject - public RegionToEndpointOrProviderIfNull(@Provider String defaultProvider, @Provider URI defaultUri, - @Region Map regionToEndpoint) { + public RegionToEndpointOrProviderIfNull(@Provider String defaultProvider, @Provider Supplier defaultUri, + @Region Supplier>> regionToEndpointSupplier) { this.defaultProvider = checkNotNull(defaultProvider, "defaultProvider"); this.defaultUri = checkNotNull(defaultUri, "defaultUri"); - this.regionToEndpoint = checkNotNull(regionToEndpoint, "regionToEndpoint"); + this.regionToEndpointSupplier = checkNotNull(regionToEndpointSupplier, "regionToEndpointSupplier"); } @Override public URI apply(@Nullable Object from) { if (from == null || from.equals(defaultProvider)) - return defaultUri; + return defaultUri.get(); checkArgument(from instanceof String, "region is a String argument"); + Map> regionToEndpoint = regionToEndpointSupplier.get(); checkArgument(regionToEndpoint.containsKey(from), "requested location %s, which is not in the configured locations: %s", from, regionToEndpoint); - return regionToEndpoint.get(from); + return regionToEndpoint.get(from).get(); } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java b/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java index 51ae51cbf3..bc18f3aac1 100644 --- a/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java +++ b/core/src/main/java/org/jclouds/location/functions/ZoneToEndpoint.java @@ -18,8 +18,8 @@ */ package org.jclouds.location.functions; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; import java.net.URI; import java.util.Map; @@ -31,6 +31,7 @@ import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Zone; import com.google.common.base.Function; +import com.google.common.base.Supplier; /** * @@ -39,17 +40,20 @@ import com.google.common.base.Function; @Singleton public class ZoneToEndpoint implements Function { - private final Map zoneToEndpoint; + private final Supplier>> zoneToEndpointSupplier; @Inject - public ZoneToEndpoint(@Zone Map zoneToEndpoint) { - this.zoneToEndpoint = checkNotNull(zoneToEndpoint, "zoneToEndpoint"); - checkArgument(zoneToEndpoint.size() > 0, "no zone name to endpoint mappings configured!"); + public ZoneToEndpoint(@Zone Supplier>> zoneToEndpointSupplier) { + this.zoneToEndpointSupplier = checkNotNull(zoneToEndpointSupplier, "zoneToEndpointSupplier"); } @Override public URI apply(@Nullable Object from) { checkArgument(from != null && from instanceof String, "you must specify a zone, as a String argument"); - return zoneToEndpoint.get(from); + Map> zoneToEndpoint = zoneToEndpointSupplier.get(); + checkState(zoneToEndpoint.size() > 0, "no zone name to endpoint mappings configured!"); + checkArgument(zoneToEndpoint.containsKey(from), + "requested location %s, which is not in the configured locations: %s", from, zoneToEndpoint); + return zoneToEndpoint.get(from).get(); } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/predicates/LocationPredicates.java b/core/src/main/java/org/jclouds/location/predicates/LocationPredicates.java index 73e47226c4..3719cf3c00 100644 --- a/core/src/main/java/org/jclouds/location/predicates/LocationPredicates.java +++ b/core/src/main/java/org/jclouds/location/predicates/LocationPredicates.java @@ -33,6 +33,24 @@ import com.google.common.base.Predicate; */ public class LocationPredicates { + public static Predicate isProvider() { + return IsProvider.INSTANCE; + } + + @Singleton + static enum IsProvider implements Predicate { + INSTANCE; + @Override + public boolean apply(Location input) { + return input.getScope() == LocationScope.PROVIDER; + } + + @Override + public String toString() { + return "isProvider()"; + } + } + public static Predicate isZone() { return IsZone.INSTANCE; } diff --git a/core/src/main/java/org/jclouds/location/config/JustProviderLocationModule.java b/core/src/main/java/org/jclouds/location/suppliers/ImplicitLocationSupplier.java similarity index 54% rename from core/src/main/java/org/jclouds/location/config/JustProviderLocationModule.java rename to core/src/main/java/org/jclouds/location/suppliers/ImplicitLocationSupplier.java index 9e4273f268..85d25223cc 100644 --- a/core/src/main/java/org/jclouds/location/config/JustProviderLocationModule.java +++ b/core/src/main/java/org/jclouds/location/suppliers/ImplicitLocationSupplier.java @@ -16,40 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.config; - -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; +package org.jclouds.location.suppliers; import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.JustProvider; -import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; -import org.jclouds.rest.AuthorizationException; +import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstRegionOptionallyMatchingRegionId; import com.google.common.base.Supplier; -import com.google.inject.TypeLiteral; +import com.google.inject.ImplementedBy; /** * * @author Adrian Cole - * */ -public class JustProviderLocationModule extends LocationModule { - public JustProviderLocationModule() { - super(); - } - - public JustProviderLocationModule(AtomicReference authException) { - super(authException); - } - - @Override - protected void configure() { - bind(new TypeLiteral>>() { - }).to(JustProvider.class); - bind(new TypeLiteral>() { - }).to(OnlyLocationOrFirstZone.class); - super.configure(); - } +@ImplementedBy(OnlyLocationOrFirstRegionOptionallyMatchingRegionId.class) +public interface ImplicitLocationSupplier extends Supplier { } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/ImplicitRegionIdSupplier.java b/core/src/main/java/org/jclouds/location/suppliers/ImplicitRegionIdSupplier.java new file mode 100644 index 0000000000..b9b98c63bf --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/ImplicitRegionIdSupplier.java @@ -0,0 +1,33 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import org.jclouds.location.suppliers.implicit.GetRegionIdMatchingProviderURIOrNull; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + * + * @author Adrian Cole + */ +@ImplementedBy(GetRegionIdMatchingProviderURIOrNull.class) +public interface ImplicitRegionIdSupplier extends Supplier { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/LocationIdToIso3166CodesSupplier.java b/core/src/main/java/org/jclouds/location/suppliers/LocationIdToIso3166CodesSupplier.java new file mode 100644 index 0000000000..cfe0a65a27 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/LocationIdToIso3166CodesSupplier.java @@ -0,0 +1,38 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.util.Map; +import java.util.Set; + +import org.jclouds.location.suppliers.fromconfig.LocationIdToIso3166CodesFromConfiguration; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + * + + * + * @author Adrian Cole + */ +@ImplementedBy(LocationIdToIso3166CodesFromConfiguration.class) +public interface LocationIdToIso3166CodesSupplier extends Supplier>>> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/config/RegionsLocationModule.java b/core/src/main/java/org/jclouds/location/suppliers/LocationsSupplier.java similarity index 60% rename from core/src/main/java/org/jclouds/location/config/RegionsLocationModule.java rename to core/src/main/java/org/jclouds/location/suppliers/LocationsSupplier.java index db5c321656..2bd00c3a54 100644 --- a/core/src/main/java/org/jclouds/location/config/RegionsLocationModule.java +++ b/core/src/main/java/org/jclouds/location/suppliers/LocationsSupplier.java @@ -16,31 +16,21 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.config; +package org.jclouds.location.suppliers; import java.util.Set; import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.OnlyLocationOrFirstRegionOptionallyMatchingRegionId; -import org.jclouds.location.suppliers.RegionToProviderOrJustProvider; +import org.jclouds.location.suppliers.all.ZoneToRegionToProviderOrJustProvider; import com.google.common.base.Supplier; -import com.google.inject.TypeLiteral; +import com.google.inject.ImplementedBy; /** * * @author Adrian Cole - * */ -public class RegionsLocationModule extends LocationModule { - - @Override - protected void configure() { - bind(new TypeLiteral>>() { - }).to(RegionToProviderOrJustProvider.class); - bind(new TypeLiteral>() { - }).to(OnlyLocationOrFirstRegionOptionallyMatchingRegionId.class); - super.configure(); - } +@ImplementedBy(ZoneToRegionToProviderOrJustProvider.class) +public interface LocationsSupplier extends Supplier> { } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/ProviderURISupplier.java b/core/src/main/java/org/jclouds/location/suppliers/ProviderURISupplier.java new file mode 100644 index 0000000000..079b586c8e --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/ProviderURISupplier.java @@ -0,0 +1,31 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.net.URI; + +import org.jclouds.location.suppliers.fromconfig.ProviderURIFromConfiguration; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +@ImplementedBy(ProviderURIFromConfiguration.class) +public interface ProviderURISupplier extends Supplier { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/RegionIdToURISupplier.java b/core/src/main/java/org/jclouds/location/suppliers/RegionIdToURISupplier.java new file mode 100644 index 0000000000..cb8542f807 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/RegionIdToURISupplier.java @@ -0,0 +1,37 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.net.URI; +import java.util.Map; + +import org.jclouds.location.suppliers.fromconfig.RegionIdToURIFromConfigurationOrDefaultToProvider; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + * + * + * @author Adrian Cole + */ +@ImplementedBy(RegionIdToURIFromConfigurationOrDefaultToProvider.class) +public interface RegionIdToURISupplier extends Supplier>> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/RegionIdToZoneIdsSupplier.java b/core/src/main/java/org/jclouds/location/suppliers/RegionIdToZoneIdsSupplier.java new file mode 100644 index 0000000000..019c5b6c00 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/RegionIdToZoneIdsSupplier.java @@ -0,0 +1,36 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.util.Map; +import java.util.Set; + +import org.jclouds.location.suppliers.fromconfig.RegionIdToZoneIdsFromConfiguration; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + + * @author Adrian Cole + */ +@ImplementedBy(RegionIdToZoneIdsFromConfiguration.class) +public interface RegionIdToZoneIdsSupplier extends Supplier>>> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/RegionIdsSupplier.java b/core/src/main/java/org/jclouds/location/suppliers/RegionIdsSupplier.java new file mode 100644 index 0000000000..16ef1482b2 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/RegionIdsSupplier.java @@ -0,0 +1,35 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.util.Set; + +import org.jclouds.location.suppliers.fromconfig.RegionIdsFromConfiguration; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + + * @author Adrian Cole + */ +@ImplementedBy(RegionIdsFromConfiguration.class) +public interface RegionIdsSupplier extends Supplier> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/ZoneIdToURISupplier.java b/core/src/main/java/org/jclouds/location/suppliers/ZoneIdToURISupplier.java new file mode 100644 index 0000000000..4b8e31235e --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/ZoneIdToURISupplier.java @@ -0,0 +1,37 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.net.URI; +import java.util.Map; + +import org.jclouds.location.suppliers.fromconfig.ZoneIdToURIFromConfigurationOrDefaultToProvider; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + * + * + * @author Adrian Cole + */ +@ImplementedBy(ZoneIdToURIFromConfigurationOrDefaultToProvider.class) +public interface ZoneIdToURISupplier extends Supplier>> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/ZoneIdsSupplier.java b/core/src/main/java/org/jclouds/location/suppliers/ZoneIdsSupplier.java new file mode 100644 index 0000000000..8f9caeb456 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/ZoneIdsSupplier.java @@ -0,0 +1,35 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers; + +import java.util.Set; + +import org.jclouds.location.suppliers.fromconfig.ZoneIdsFromConfiguration; + +import com.google.common.base.Supplier; +import com.google.inject.ImplementedBy; + +/** + * + * @author Adrian Cole + */ +@ImplementedBy(ZoneIdsFromConfiguration.class) +public interface ZoneIdsSupplier extends Supplier> { + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/ZoneToRegionToProviderOrJustProvider.java b/core/src/main/java/org/jclouds/location/suppliers/ZoneToRegionToProviderOrJustProvider.java deleted file mode 100644 index 89d4a56ed3..0000000000 --- a/core/src/main/java/org/jclouds/location/suppliers/ZoneToRegionToProviderOrJustProvider.java +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.location.suppliers; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Maps.uniqueIndex; - -import java.net.URI; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.domain.Location; -import org.jclouds.domain.LocationBuilder; -import org.jclouds.domain.LocationScope; -import org.jclouds.location.Iso3166; -import org.jclouds.location.Provider; -import org.jclouds.location.Zone; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSet.Builder; - -/** - * - * @author Adrian Cole - */ -@Singleton -public class ZoneToRegionToProviderOrJustProvider extends RegionToProviderOrJustProvider { - private final Map zoneToRegion; - private Map> isoCodesById; - - @Inject - ZoneToRegionToProviderOrJustProvider(@Iso3166 Set isoCodes, @Provider String providerName, - @Provider URI endpoint, @Iso3166 Map> isoCodesById, - @Zone Map zoneToRegion) { - super(isoCodes, providerName, endpoint, ImmutableSet.copyOf(checkNotNull(zoneToRegion, "zoneToRegion").values()), - isoCodesById); - this.zoneToRegion = zoneToRegion; - this.isoCodesById = checkNotNull(isoCodesById, "isoCodesById"); - } - - @Override - public Set get() { - Builder locations = buildJustProviderOrRegions(); - ImmutableMap idToLocation = uniqueIndex(locations.build(), new Function() { - @Override - public String apply(Location from) { - return from.getId(); - } - }); - if (zoneToRegion.size() == 1) - return locations.build(); - for (String zone : zoneToRegion.keySet()) { - Location parent = idToLocation.get(zoneToRegion.get(zone)); - LocationBuilder builder = new LocationBuilder().scope(LocationScope.ZONE).id(zone).description(zone).parent( - parent); - if (isoCodesById.containsKey(zone)) - builder.iso3166Codes(isoCodesById.get(zone)); - // be cautious.. only inherit iso codes if the parent is a region - // regions may be added dynamically, and we prefer to inherit an - // empty set of codes from a region, then a provider, whose code - // are likely hard-coded. - else if (parent.getScope() == LocationScope.REGION) - builder.iso3166Codes(parent.getIso3166Codes()); - locations.add(builder.build()); - } - return locations.build(); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/JustProvider.java b/core/src/main/java/org/jclouds/location/suppliers/all/JustProvider.java similarity index 79% rename from core/src/main/java/org/jclouds/location/suppliers/JustProvider.java rename to core/src/main/java/org/jclouds/location/suppliers/all/JustProvider.java index f42551d0a3..a249aefee9 100644 --- a/core/src/main/java/org/jclouds/location/suppliers/JustProvider.java +++ b/core/src/main/java/org/jclouds/location/suppliers/all/JustProvider.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.all; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,20 +42,20 @@ import com.google.common.collect.ImmutableSet; @Singleton public class JustProvider implements Supplier> { private final String providerName; - private final URI endpoint; - private final Set isoCodes; + private final URI endpointSupplier; + private final Set isoCodesSupplier; @Inject - public JustProvider(@Provider String providerName, @Provider URI endpoint, @Iso3166 Set isoCodes) { + public JustProvider(@Provider String providerName, @Provider URI endpointSupplier, @Iso3166 Set isoCodesSupplier) { this.providerName = checkNotNull(providerName, "providerName"); - this.endpoint = checkNotNull(endpoint, "endpoint"); - this.isoCodes = checkNotNull(isoCodes, "isoCodes"); + this.endpointSupplier = checkNotNull(endpointSupplier, "endpoint"); + this.isoCodesSupplier = checkNotNull(isoCodesSupplier, "isoCodes"); } @Override public Set get() { return ImmutableSet.of(new LocationBuilder().scope(LocationScope.PROVIDER).id(providerName) - .description(endpoint.toASCIIString()).iso3166Codes(isoCodes).build()); + .description(endpointSupplier.toASCIIString()).iso3166Codes(isoCodesSupplier).build()); } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/RegionToProviderOrJustProvider.java b/core/src/main/java/org/jclouds/location/suppliers/all/RegionToProviderOrJustProvider.java similarity index 61% rename from core/src/main/java/org/jclouds/location/suppliers/RegionToProviderOrJustProvider.java rename to core/src/main/java/org/jclouds/location/suppliers/all/RegionToProviderOrJustProvider.java index b3eee0a442..17f494a550 100644 --- a/core/src/main/java/org/jclouds/location/suppliers/RegionToProviderOrJustProvider.java +++ b/core/src/main/java/org/jclouds/location/suppliers/all/RegionToProviderOrJustProvider.java @@ -16,11 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.all; import static com.google.common.base.Preconditions.checkNotNull; -import java.net.URI; import java.util.Map; import java.util.Set; @@ -31,9 +30,9 @@ import org.jclouds.domain.Location; import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationScope; import org.jclouds.location.Iso3166; -import org.jclouds.location.Provider; import org.jclouds.location.Region; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.ImmutableSet.Builder; @@ -43,37 +42,36 @@ import com.google.common.collect.ImmutableSet.Builder; * @author Adrian Cole */ @Singleton -public class RegionToProviderOrJustProvider extends JustProvider { - private final Set regions; - private final Map> isoCodesById; +public class RegionToProviderOrJustProvider implements Supplier> { + private final JustProvider justProvider; + private final Supplier> regionsSupplier; + private final Supplier>>> isoCodesByIdSupplier; @Inject - public RegionToProviderOrJustProvider(@Iso3166 Set isoCodes, @Provider String providerName, - @Provider URI endpoint, @Region Set regions, @Iso3166 Map> isoCodesById) { - super(providerName, endpoint, isoCodes); - this.regions = checkNotNull(regions, "regions"); - this.isoCodesById = checkNotNull(isoCodesById, "isoCodesById"); + public RegionToProviderOrJustProvider(JustProvider justProvider, @Region Supplier> regionsSupplier, + @Iso3166 Supplier>>> isoCodesByIdSupplier) { + this.justProvider = checkNotNull(justProvider, "justProvider"); + this.regionsSupplier = checkNotNull(regionsSupplier, "regionsSupplier"); + this.isoCodesByIdSupplier = checkNotNull(isoCodesByIdSupplier, "isoCodesByIdSupplier"); } @Override public Set get() { - return buildJustProviderOrRegions().build(); - } - - protected Builder buildJustProviderOrRegions() { Builder locations = ImmutableSet.builder(); - Location provider = Iterables.getOnlyElement(super.get()); + Location provider = Iterables.getOnlyElement(justProvider.get()); + Set regions = regionsSupplier.get(); + Map>> isoCodesById = isoCodesByIdSupplier.get(); if (regions.size() == 0) - return locations.add(provider); + return locations.add(provider).build(); else for (String region : regions) { LocationBuilder builder = new LocationBuilder().scope(LocationScope.REGION).id(region).description(region) .parent(provider); if (isoCodesById.containsKey(region)) - builder.iso3166Codes(isoCodesById.get(region)); + builder.iso3166Codes(isoCodesById.get(region).get()); locations.add(builder.build()); } - return locations; + return locations.build(); } } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/all/ZoneToRegionToProviderOrJustProvider.java b/core/src/main/java/org/jclouds/location/suppliers/all/ZoneToRegionToProviderOrJustProvider.java new file mode 100644 index 0000000000..83d3d27e77 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/all/ZoneToRegionToProviderOrJustProvider.java @@ -0,0 +1,142 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.all; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; +import org.jclouds.location.Iso3166; +import org.jclouds.location.Zone; +import org.jclouds.location.predicates.LocationPredicates; +import org.jclouds.location.suppliers.LocationsSupplier; +import org.jclouds.logging.Logger; + +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.common.collect.Sets.SetView; + +/** + * + * @author Adrian Cole + */ +@Singleton +public class ZoneToRegionToProviderOrJustProvider implements LocationsSupplier { + + @Resource + protected Logger logger = Logger.NULL; + + private final RegionToProviderOrJustProvider regionToProviderOrJustProvider; + private final Supplier> zoneIdsSupplier; + private final Supplier>>> isoCodesByIdSupplier; + private final Supplier>>> regionIdToZoneIdsSupplier; + + @Inject + ZoneToRegionToProviderOrJustProvider(RegionToProviderOrJustProvider regionToProviderOrJustProvider, + @Zone Supplier> zoneIdsSupplier, + @Iso3166 Supplier>>> isoCodesByIdSupplier, + @Zone Supplier>>> regionIdToZoneIdsSupplier) { + this.regionToProviderOrJustProvider = checkNotNull(regionToProviderOrJustProvider, + "regionToProviderOrJustProvider"); + this.zoneIdsSupplier = checkNotNull(zoneIdsSupplier, "zoneIdsSupplier"); + this.regionIdToZoneIdsSupplier = checkNotNull(regionIdToZoneIdsSupplier, "regionIdToZoneIdsSupplier"); + this.isoCodesByIdSupplier = checkNotNull(isoCodesByIdSupplier, "isoCodesByIdSupplier"); + } + + @Override + public Set get() { + Set regionsOrJustProvider = regionToProviderOrJustProvider.get(); + Set zoneIds = zoneIdsSupplier.get(); + if (zoneIds.size() == 0) + return regionsOrJustProvider; + Map zoneIdToParent = setParentOfZoneToRegionOrProvider(zoneIds, regionsOrJustProvider); + Map>> isoCodesById = isoCodesByIdSupplier.get(); + + Builder locations = ImmutableSet.builder(); + locations.addAll(regionsOrJustProvider); + for (String zoneId : zoneIdToParent.keySet()) { + Location parent = zoneIdToParent.get(zoneId); + LocationBuilder builder = new LocationBuilder().scope(LocationScope.ZONE).id(zoneId).description(zoneId) + .parent(parent); + if (isoCodesById.containsKey(zoneId)) + builder.iso3166Codes(isoCodesById.get(zoneId).get()); + // be cautious.. only inherit iso codes if the parent is a region + // regions may be added dynamically, and we prefer to inherit an + // empty set of codes from a region, then a provider, whose code + // are likely hard-coded. + else if (parent.getScope() == LocationScope.REGION) + builder.iso3166Codes(parent.getIso3166Codes()); + locations.add(builder.build()); + } + return locations.build(); + } + + private Map setParentOfZoneToRegionOrProvider(Set zoneIds, + Set locations) { + // mutable, so that we can query current state when adding. safe as its temporary + Map zoneIdToParent = Maps.newLinkedHashMap(); + + Location provider = Iterables.find(locations, LocationPredicates.isProvider(), null); + if (locations.size() == 1 && provider != null) { + for (String zone : zoneIds) + zoneIdToParent.put(zone, provider); + } else { + // note that we only call regionIdToZoneIdsSupplier if there are region locations present + // they cannot be, if the above is true + Map>> regionIdToZoneIds = regionIdToZoneIdsSupplier.get(); + for (Location region : Iterables.filter(locations, LocationPredicates.isRegion())) { + provider = region.getParent(); + if (regionIdToZoneIds.containsKey(region.getId())) { + for (String zoneId : regionIdToZoneIds.get(region.getId()).get()) + zoneIdToParent.put(zoneId, region); + } else { + logger.debug("no zones configured for region: %s", region); + } + } + } + + SetView orphans = Sets.difference(zoneIds, zoneIdToParent.keySet()); + if (orphans.size() > 0) { + // any unmatched zones should have their parents set to the provider + checkState( + provider != null, + "cannot configure zones %s as we need a parent, and the only available location [%s] is not a provider", + zoneIds, locations); + for (String orphanedZoneId : orphans) + zoneIdToParent.put(orphanedZoneId, provider); + } + + checkState(zoneIdToParent.keySet().containsAll(zoneIds), "orphaned zones: %s ", Sets.difference(zoneIds, + zoneIdToParent.keySet())); + return zoneIdToParent; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaProperties.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToIso3166CodesFromConfiguration.java similarity index 73% rename from core/src/main/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaProperties.java rename to core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToIso3166CodesFromConfiguration.java index 84a051dca3..4f47bb27b9 100644 --- a/core/src/main/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaProperties.java +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToIso3166CodesFromConfiguration.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.config; +package org.jclouds.location.suppliers.fromconfig; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES; @@ -30,45 +30,48 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.location.Iso3166; +import org.jclouds.location.suppliers.LocationIdToIso3166CodesSupplier; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap.Builder; /** * - * looks for properties bound to the naming conventions jclouds.region. - * {@code regionId} .iso3166-codes and jclouds.zone.{@code zoneId}.iso3166-codes + * looks for properties bound to the naming conventions jclouds.region. {@code regionId} + * .iso3166-codes and jclouds.zone.{@code zoneId}.iso3166-codes * * @author Adrian Cole */ @Singleton -public class ProvideIso3166CodesByLocationIdViaProperties implements javax.inject.Provider>> { +public class LocationIdToIso3166CodesFromConfiguration implements LocationIdToIso3166CodesSupplier { private final Function, Map> filterStringsBoundByName; @Inject - ProvideIso3166CodesByLocationIdViaProperties( - Function, Map> filterStringsBoundByName) { + public LocationIdToIso3166CodesFromConfiguration( + Function, Map> filterStringsBoundByName) { this.filterStringsBoundByName = checkNotNull(filterStringsBoundByName, "filterStringsBoundByName"); } @Singleton @Iso3166 @Override - public Map> get() { + public Map>> get() { Map stringsBoundWithRegionOrZonePrefix = filterStringsBoundByName.apply(new Predicate() { @Override public boolean apply(String input) { - return input.startsWith(PROPERTY_REGION) || input.startsWith(PROPERTY_ZONE); + return (input.startsWith(PROPERTY_REGION) || input.startsWith(PROPERTY_ZONE)); } }); - Builder> codes = ImmutableMap.> builder(); + Builder>> codes = ImmutableMap.>> builder(); for (String key : ImmutableSet.of(PROPERTY_REGION, PROPERTY_ZONE)) { String regionOrZoneString = stringsBoundWithRegionOrZonePrefix.get(key + "s"); if (regionOrZoneString == null) @@ -76,7 +79,8 @@ public class ProvideIso3166CodesByLocationIdViaProperties implements javax.injec for (String region : Splitter.on(',').split(regionOrZoneString)) { String isoCodes = stringsBoundWithRegionOrZonePrefix.get(key + "." + region + "." + ISO3166_CODES); if (isoCodes != null) - codes.put(region, ImmutableSet.copyOf(Splitter.on(',').split(isoCodes))); + codes.put(region, Suppliers.> ofInstance(ImmutableSet.copyOf(Splitter.on(',') + .split(isoCodes)))); } } return codes.build(); diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToURIFromConfigurationOrDefaultToProvider.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToURIFromConfigurationOrDefaultToProvider.java new file mode 100644 index 0000000000..5cc3b45a8e --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/LocationIdToURIFromConfigurationOrDefaultToProvider.java @@ -0,0 +1,78 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.ENDPOINT; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.logging.Logger; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.inject.assistedinject.Assisted; + +@Singleton +public class LocationIdToURIFromConfigurationOrDefaultToProvider implements Supplier>>{ + + @Resource + protected Logger logger = Logger.NULL; + + protected final ValueOfConfigurationKeyOrNull config; + protected final Supplier> locationIds; + protected final Supplier providerURI; + protected final String configPrefix; + + @Inject + public LocationIdToURIFromConfigurationOrDefaultToProvider(ValueOfConfigurationKeyOrNull config, @Provider Supplier providerURI, @Assisted Supplier> locationIds, + @Assisted String configPrefix) { + this.config = config; + this.locationIds = locationIds; + this.providerURI = providerURI; + this.configPrefix = configPrefix; + } + + @Override + public Map> get() { + Builder> locations = ImmutableMap.> builder(); + for (String location : locationIds.get()) { + String configKey = configPrefix + "." + location + "." + ENDPOINT; + String locationUri = config.apply(configKey); + if (locationUri == null) { + logger.debug("config key %s not present, defaulting to %s", configKey, providerURI); + locations.put(location, providerURI); + } else { + locations.put(location, Suppliers.ofInstance(URI.create(locationUri))); + + } + } + return locations.build(); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ProviderURIFromConfiguration.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ProviderURIFromConfiguration.java new file mode 100644 index 0000000000..8ac08ad01b --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ProviderURIFromConfiguration.java @@ -0,0 +1,39 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.Constants.PROPERTY_ENDPOINT; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.location.suppliers.ProviderURISupplier; +import org.jclouds.rest.suppliers.URIFromStringSupplier; + +@Singleton +public class ProviderURIFromConfiguration extends URIFromStringSupplier implements + ProviderURISupplier { + @Inject + protected ProviderURIFromConfiguration(@Named(PROPERTY_ENDPOINT) String endpoint) { + super(checkNotNull(endpoint, PROPERTY_ENDPOINT)); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToURIFromConfigurationOrDefaultToProvider.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToURIFromConfigurationOrDefaultToProvider.java new file mode 100644 index 0000000000..e9733add6f --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToURIFromConfigurationOrDefaultToProvider.java @@ -0,0 +1,51 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION; + +import java.net.URI; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.location.Region; +import org.jclouds.location.suppliers.RegionIdToURISupplier; + +import com.google.common.base.Supplier; + +/** + * + * looks for properties bound to the naming convention jclouds.region.{@code regionId}.endpoint + * + * @author Adrian Cole + */ +@Singleton +public class RegionIdToURIFromConfigurationOrDefaultToProvider extends LocationIdToURIFromConfigurationOrDefaultToProvider implements RegionIdToURISupplier { + + @Inject + protected RegionIdToURIFromConfigurationOrDefaultToProvider(ValueOfConfigurationKeyOrNull config, @Provider Supplier providerURI, + @Region Supplier> regionIds) { + super(config, providerURI, regionIds, PROPERTY_REGION); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToZoneIdsFromConfiguration.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToZoneIdsFromConfiguration.java new file mode 100644 index 0000000000..3c0a3235d1 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdToZoneIdsFromConfiguration.java @@ -0,0 +1,91 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION; + +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.location.Region; +import org.jclouds.location.Zone; +import org.jclouds.location.suppliers.RegionIdToZoneIdsSupplier; +import org.jclouds.logging.Logger; + +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableMap.Builder; + +/** + * + * looks for properties bound to the naming convention jclouds.location.region.{@code regionId} + * .zones + * + * @author Adrian Cole + */ +@Singleton +public class RegionIdToZoneIdsFromConfiguration implements RegionIdToZoneIdsSupplier { + + @Resource + protected Logger logger = Logger.NULL; + + private final ValueOfConfigurationKeyOrNull config; + private final String provider; + private final Supplier> regionsSupplier; + + @Inject + protected RegionIdToZoneIdsFromConfiguration(ValueOfConfigurationKeyOrNull config, @Provider String provider, + @Region Supplier> regionsSupplier) { + this.config = config; + this.provider = provider; + this.regionsSupplier = regionsSupplier; + } + + @Singleton + @Zone + @Override + public Map>> get() { + Set regions = regionsSupplier.get(); + if (regions.size() == 0) { + logger.debug("no regions configured for provider %s", provider); + return ImmutableMap.of(); + } + Builder>> regionToZones = ImmutableMap.>> builder(); + for (String region : regions) { + String configKey = PROPERTY_REGION + "." + region + ".zones"; + String zones = config.apply(configKey); + if (zones == null) + logger.debug("config key %s not present", configKey); + else + regionToZones.put(region, Suppliers.> ofInstance(ImmutableSet.copyOf(Splitter.on(',').split( + zones)))); + } + return regionToZones.build(); + + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdsFromConfiguration.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdsFromConfiguration.java new file mode 100644 index 0000000000..d45a5c88f7 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/RegionIdsFromConfiguration.java @@ -0,0 +1,45 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.location.suppliers.RegionIdsSupplier; + + +/** + * + * looks for properties bound to the naming convention jclouds.regions + * + * @author Adrian Cole + */ +@Singleton +public class RegionIdsFromConfiguration extends SplitConfigurationKey implements RegionIdsSupplier { + + @Inject + protected RegionIdsFromConfiguration(ValueOfConfigurationKeyOrNull config, @Provider String provider) { + super(config, provider, PROPERTY_REGIONS); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/SplitConfigurationKey.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/SplitConfigurationKey.java new file mode 100644 index 0000000000..333736cb02 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/SplitConfigurationKey.java @@ -0,0 +1,63 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.logging.Logger; + +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableSet; +import com.google.inject.assistedinject.Assisted; + +@Singleton +public class SplitConfigurationKey implements Supplier> { + + @Resource + protected Logger logger = Logger.NULL; + + protected final ValueOfConfigurationKeyOrNull config; + protected final String provider; + protected final String configKey; + + public SplitConfigurationKey(ValueOfConfigurationKeyOrNull config, @Provider String provider, + @Assisted String configKey) { + this.config = config; + this.provider = provider; + this.configKey = configKey; + } + + @Override + public Set get() { + String regionString = config.apply(configKey); + if (regionString == null) { + logger.debug("no %s configured for provider %s", configKey, provider); + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(Splitter.on(',').split(regionString)); + } + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdToURIFromConfigurationOrDefaultToProvider.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdToURIFromConfigurationOrDefaultToProvider.java new file mode 100644 index 0000000000..7d07469eb4 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdToURIFromConfigurationOrDefaultToProvider.java @@ -0,0 +1,51 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONE; + +import java.net.URI; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.location.Zone; +import org.jclouds.location.suppliers.ZoneIdToURISupplier; + +import com.google.common.base.Supplier; + +/** + * + * looks for properties bound to the naming convention jclouds.zone.{@code zoneId}.endpoint + * + * @author Adrian Cole + */ +@Singleton +public class ZoneIdToURIFromConfigurationOrDefaultToProvider extends LocationIdToURIFromConfigurationOrDefaultToProvider implements ZoneIdToURISupplier { + + @Inject + protected ZoneIdToURIFromConfigurationOrDefaultToProvider(ValueOfConfigurationKeyOrNull config, @Provider Supplier providerURI, + @Zone Supplier> zoneIds) { + super(config, providerURI, zoneIds, PROPERTY_ZONE); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdsFromConfiguration.java b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdsFromConfiguration.java new file mode 100644 index 0000000000..9a5c84a96b --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/fromconfig/ZoneIdsFromConfiguration.java @@ -0,0 +1,45 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.fromconfig; + +import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONES; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.location.Provider; +import org.jclouds.location.suppliers.ZoneIdsSupplier; + + +/** + * + * looks for properties bound to the naming convention jclouds.zones + * + * @author Adrian Cole + */ +@Singleton +public class ZoneIdsFromConfiguration extends SplitConfigurationKey implements ZoneIdsSupplier { + + @Inject + protected ZoneIdsFromConfiguration(ValueOfConfigurationKeyOrNull config, @Provider String provider) { + super(config, provider, PROPERTY_ZONES); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/implicit/GetRegionIdMatchingProviderURIOrNull.java b/core/src/main/java/org/jclouds/location/suppliers/implicit/GetRegionIdMatchingProviderURIOrNull.java new file mode 100644 index 0000000000..db5bfd1830 --- /dev/null +++ b/core/src/main/java/org/jclouds/location/suppliers/implicit/GetRegionIdMatchingProviderURIOrNull.java @@ -0,0 +1,44 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.location.suppliers.implicit; + +import java.net.URI; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.location.Provider; +import org.jclouds.location.Region; +import org.jclouds.location.suppliers.ImplicitRegionIdSupplier; +import org.jclouds.suppliers.SupplyKeyMatchingValueOrNull; + +import com.google.common.base.Supplier; + +@Singleton +public class GetRegionIdMatchingProviderURIOrNull extends SupplyKeyMatchingValueOrNull implements + ImplicitRegionIdSupplier { + + @Inject + public GetRegionIdMatchingProviderURIOrNull(@Region Supplier>> supplier, + @Provider Supplier providerUri) { + super(supplier, providerUri); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java b/core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java similarity index 79% rename from core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java rename to core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java index 316c7b7845..27894bb820 100644 --- a/core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java +++ b/core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionId.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.implicit; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.getOnlyElement; @@ -34,9 +34,9 @@ import javax.inject.Singleton; import org.jclouds.collect.Memoized; import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; -import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Region; import org.jclouds.location.functions.ToIdAndScope; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; import com.google.common.base.Predicate; import com.google.common.base.Predicates; @@ -47,22 +47,23 @@ import com.google.common.collect.Iterables; * @author Adrian Cole */ @Singleton -public class OnlyLocationOrFirstRegionOptionallyMatchingRegionId implements Supplier { - - private final Predicate locationPredicate; +public class OnlyLocationOrFirstRegionOptionallyMatchingRegionId implements ImplicitLocationSupplier { + private final Supplier regionSupplier; private final Supplier> locationsSupplier; @Inject - OnlyLocationOrFirstRegionOptionallyMatchingRegionId(@Nullable @Region String region, - @Memoized Supplier> locationsSupplier) { - this.locationPredicate = region == null ? Predicates.or(isZone(), isRegion()) - : isZoneOrRegionWhereRegionIdEquals(region); + OnlyLocationOrFirstRegionOptionallyMatchingRegionId(@Region Supplier regionSupplier, + @Memoized Supplier> locationsSupplier) { + this.regionSupplier = checkNotNull(regionSupplier, "regionSupplier"); this.locationsSupplier = checkNotNull(locationsSupplier, "locationsSupplier"); } @Override @Singleton public Location get() { + String region = regionSupplier.get(); + Predicate locationPredicate = region == null ? Predicates.or(isZone(), isRegion()) + : isZoneOrRegionWhereRegionIdEquals(region); Set locations = locationsSupplier.get(); if (locationsSupplier.get().size() == 1) return getOnlyElement(locationsSupplier.get()); diff --git a/core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZone.java b/core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZone.java similarity index 92% rename from core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZone.java rename to core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZone.java index 77f44b1ac5..394f6d1727 100644 --- a/core/src/main/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZone.java +++ b/core/src/main/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZone.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.implicit; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Iterables.find; @@ -33,6 +33,7 @@ import javax.inject.Singleton; import org.jclouds.collect.Memoized; import org.jclouds.domain.Location; import org.jclouds.location.functions.ToIdAndScope; +import org.jclouds.location.suppliers.ImplicitLocationSupplier; import com.google.common.base.Supplier; @@ -42,7 +43,7 @@ import com.google.common.base.Supplier; * */ @Singleton -public class OnlyLocationOrFirstZone implements Supplier { +public class OnlyLocationOrFirstZone implements ImplicitLocationSupplier { private final Supplier> locationsSupplier; diff --git a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java index 74340d02a9..c77a721aa8 100644 --- a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java +++ b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java @@ -19,78 +19,44 @@ package org.jclouds.rest; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Predicates.equalTo; import static com.google.common.base.Predicates.instanceOf; -import static com.google.common.base.Predicates.not; -import static com.google.common.base.Splitter.on; import static com.google.common.collect.Iterables.addAll; import static com.google.common.collect.Iterables.any; -import static com.google.common.collect.Iterables.filter; import static com.google.inject.Scopes.SINGLETON; import static com.google.inject.util.Types.newParameterizedType; -import static org.jclouds.Constants.PROPERTY_API; -import static org.jclouds.Constants.PROPERTY_API_VERSION; -import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; -import static org.jclouds.Constants.PROPERTY_CREDENTIAL; -import static org.jclouds.Constants.PROPERTY_ENDPOINT; -import static org.jclouds.Constants.PROPERTY_IDENTITY; -import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; -import static org.jclouds.Constants.PROPERTY_PROVIDER; -import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; -import java.net.URI; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Properties; -import java.util.Set; import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; import org.jclouds.concurrent.MoreExecutors; import org.jclouds.concurrent.SingleThreaded; import org.jclouds.concurrent.config.ConfiguresExecutorService; import org.jclouds.concurrent.config.ExecutorServiceModule; -import org.jclouds.config.ValueOfConfigurationKeyOrNull; -import org.jclouds.domain.Credentials; import org.jclouds.http.RequiresHttp; import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; -import org.jclouds.internal.FilterStringsBoundToInjectorByName; -import org.jclouds.javax.annotation.Nullable; import org.jclouds.lifecycle.config.LifeCycleModule; -import org.jclouds.location.Iso3166; -import org.jclouds.location.Provider; -import org.jclouds.location.config.ProvideIso3166CodesByLocationIdViaProperties; import org.jclouds.logging.config.LoggingModule; import org.jclouds.logging.jdk.config.JDKLoggingModule; -import org.jclouds.rest.annotations.Api; -import org.jclouds.rest.annotations.ApiVersion; -import org.jclouds.rest.annotations.BuildVersion; -import org.jclouds.rest.annotations.Credential; -import org.jclouds.rest.annotations.Identity; +import org.jclouds.rest.config.BindPropertiesToAnnotations; import org.jclouds.rest.config.CredentialStoreModule; import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestModule; import org.jclouds.rest.internal.RestContextImpl; -import org.jclouds.util.Maps2; import org.nnsoft.guice.rocoto.Rocoto; import org.nnsoft.guice.rocoto.configuration.ConfigurationModule; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; import com.google.common.util.concurrent.ExecutionList; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; -import com.google.inject.Provides; import com.google.inject.Stage; import com.google.inject.TypeLiteral; @@ -108,115 +74,6 @@ import com.google.inject.TypeLiteral; * @see RestContext */ public class RestContextBuilder { - - static class BindPropertiesToAnnotations extends ConfigurationModule { - - @Provides - @Singleton - @Named("TIMEOUTS") - protected Map timeouts(Function, Map> filterStringsBoundByName) { - Map stringBoundWithTimeoutPrefix = filterStringsBoundByName.apply(new Predicate() { - - @Override - public boolean apply(String input) { - return input.startsWith(PROPERTY_TIMEOUTS_PREFIX); - } - - }); - - Map longsByName = Maps.transformValues(stringBoundWithTimeoutPrefix, new Function() { - - @Override - public Long apply(String input) { - return Long.valueOf(String.valueOf(input)); - } - - }); - return Maps2.transformKeys(longsByName, new Function() { - - @Override - public String apply(String input) { - return input.replaceFirst(PROPERTY_TIMEOUTS_PREFIX, ""); - } - - }); - - } - - @Provides - @Singleton - @Provider - protected String bindProvider(@Named(PROPERTY_PROVIDER) String in){ - return in; - } - - @Provides - @Singleton - @Provider - protected URI bindProviderEndpoint(@Named(PROPERTY_ENDPOINT) String in){ - return URI.create(in); - } - - @Provides - @Singleton - @Iso3166 - protected Set bindIsoCodes(@Named(PROPERTY_ISO3166_CODES) String in){ - return ImmutableSet.copyOf(filter(on(',').split( in), - not(equalTo("")))); - } - - @Provides - @Singleton - @Api - protected String bindApi(@Named(PROPERTY_API) String in){ - return in; - } - - @Provides - @Singleton - @ApiVersion - protected String bindApiVersion(@Named(PROPERTY_API_VERSION) String in){ - return in; - } - - @Provides - @Singleton - @BuildVersion - protected String bindBuildVersion(@Named(PROPERTY_BUILD_VERSION) String in){ - return in; - } - - @Provides - @Singleton - @Identity - protected String bindIdentity(@Named(PROPERTY_IDENTITY) String in){ - return in; - } - - @Provides - @Singleton - @Credential - @Nullable - protected String bindCredential(ValueOfConfigurationKeyOrNull config){ - return config.apply(PROPERTY_CREDENTIAL); - } - - @Provides - @Singleton - @Provider - protected Credentials bindProviderCredentials(@Identity String identity, @Nullable @Credential String credential){ - return new Credentials(identity, credential); - } - - @Override - protected void bindConfigurations() { - bind(new TypeLiteral, Map>>() { - }).to(FilterStringsBoundToInjectorByName.class); - bind(new TypeLiteral>>() { - }).annotatedWith(Iso3166.class).toProvider(ProvideIso3166CodesByLocationIdViaProperties.class); - } - } - protected Properties properties; protected List modules = new ArrayList(3); protected Class asyncClientType; diff --git a/core/src/main/java/org/jclouds/rest/config/BindPropertiesToAnnotations.java b/core/src/main/java/org/jclouds/rest/config/BindPropertiesToAnnotations.java new file mode 100644 index 0000000000..855fc44fec --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/config/BindPropertiesToAnnotations.java @@ -0,0 +1,168 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.config; + +import static com.google.common.base.Predicates.equalTo; +import static com.google.common.base.Predicates.not; +import static com.google.common.base.Splitter.on; +import static com.google.common.collect.Iterables.filter; +import static org.jclouds.Constants.PROPERTY_API; +import static org.jclouds.Constants.PROPERTY_API_VERSION; +import static org.jclouds.Constants.PROPERTY_BUILD_VERSION; +import static org.jclouds.Constants.PROPERTY_CREDENTIAL; +import static org.jclouds.Constants.PROPERTY_ENDPOINT; +import static org.jclouds.Constants.PROPERTY_IDENTITY; +import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; +import static org.jclouds.Constants.PROPERTY_PROVIDER; +import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.config.ValueOfConfigurationKeyOrNull; +import org.jclouds.domain.Credentials; +import org.jclouds.internal.FilterStringsBoundToInjectorByName; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.location.Iso3166; +import org.jclouds.location.Provider; +import org.jclouds.rest.annotations.Api; +import org.jclouds.rest.annotations.ApiVersion; +import org.jclouds.rest.annotations.BuildVersion; +import org.jclouds.rest.annotations.Credential; +import org.jclouds.rest.annotations.Identity; +import org.jclouds.util.Maps2; +import org.nnsoft.guice.rocoto.configuration.ConfigurationModule; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; + +public class BindPropertiesToAnnotations extends ConfigurationModule { + + @Provides + @Singleton + @Named("TIMEOUTS") + protected Map timeouts(Function, Map> filterStringsBoundByName) { + Map stringBoundWithTimeoutPrefix = filterStringsBoundByName.apply(new Predicate() { + + @Override + public boolean apply(String input) { + return input.startsWith(PROPERTY_TIMEOUTS_PREFIX); + } + + }); + + Map longsByName = Maps.transformValues(stringBoundWithTimeoutPrefix, new Function() { + + @Override + public Long apply(String input) { + return Long.valueOf(String.valueOf(input)); + } + + }); + return Maps2.transformKeys(longsByName, new Function() { + + @Override + public String apply(String input) { + return input.replaceFirst(PROPERTY_TIMEOUTS_PREFIX, ""); + } + + }); + + } + + @Provides + @Singleton + @Provider + protected String bindProvider(@Named(PROPERTY_PROVIDER) String in){ + return in; + } + + @Provides + @Singleton + @Provider + protected URI bindProviderEndpoint(@Named(PROPERTY_ENDPOINT) String in){ + return URI.create(in); + } + + @Provides + @Singleton + @Iso3166 + protected Set bindIsoCodes(@Named(PROPERTY_ISO3166_CODES) String in){ + return ImmutableSet.copyOf(filter(on(',').split( in), + not(equalTo("")))); + } + + @Provides + @Singleton + @Api + protected String bindApi(@Named(PROPERTY_API) String in){ + return in; + } + + @Provides + @Singleton + @ApiVersion + protected String bindApiVersion(@Named(PROPERTY_API_VERSION) String in){ + return in; + } + + @Provides + @Singleton + @BuildVersion + protected String bindBuildVersion(@Named(PROPERTY_BUILD_VERSION) String in){ + return in; + } + + @Provides + @Singleton + @Identity + protected String bindIdentity(@Named(PROPERTY_IDENTITY) String in){ + return in; + } + + @Provides + @Singleton + @Credential + @Nullable + protected String bindCredential(ValueOfConfigurationKeyOrNull config){ + return config.apply(PROPERTY_CREDENTIAL); + } + + @Provides + @Singleton + @Provider + protected Credentials bindProviderCredentials(@Identity String identity, @Nullable @Credential String credential){ + return new Credentials(identity, credential); + } + + @Override + protected void bindConfigurations() { + bind(new TypeLiteral, Map>>() { + }).to(FilterStringsBoundToInjectorByName.class); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/rest/config/RestClientModule.java b/core/src/main/java/org/jclouds/rest/config/RestClientModule.java index 871a029a80..93c9f777d8 100644 --- a/core/src/main/java/org/jclouds/rest/config/RestClientModule.java +++ b/core/src/main/java/org/jclouds/rest/config/RestClientModule.java @@ -18,21 +18,22 @@ */ package org.jclouds.rest.config; +import java.net.URI; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import javax.inject.Named; import javax.inject.Singleton; -import org.jclouds.Constants; -import org.jclouds.domain.Credentials; import org.jclouds.http.RequiresHttp; import org.jclouds.internal.ClassMethodArgs; -import org.jclouds.javax.annotation.Nullable; -import org.jclouds.location.Provider; +import org.jclouds.location.config.LocationModule; +import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.RestContext; import org.jclouds.rest.internal.RestContextImpl; +import com.google.common.base.Supplier; import com.google.common.cache.CacheBuilder; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; @@ -49,10 +50,13 @@ import com.google.inject.util.Types; @ConfiguresRestClient @RequiresHttp public class RestClientModule extends AbstractModule { - + public final static TypeLiteral> URI_SUPPLIER_TYPE = new TypeLiteral>() { + }; + protected final Class asyncClientType; protected final Class syncClientType; protected final Map, Class> delegates; + protected final AtomicReference authException = new AtomicReference(); public RestClientModule(Class syncClientType, Class asyncClientType, Map, Class> delegates) { @@ -65,10 +69,16 @@ public class RestClientModule extends AbstractModule { this(syncClientType, asyncClientType, ImmutableMap ., Class> of(syncClientType, asyncClientType)); } + + protected void installLocations() { + install(new LocationModule()); + } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected void configure() { + // this will help short circuit scenarios that can otherwise lock out users + bind(new TypeLiteral>(){}).toInstance(authException); // Ensures the restcontext can be looked up without generic types. bind(new TypeLiteral() { }).to( @@ -82,6 +92,7 @@ public class RestClientModule extends AbstractModule { bindClient(); bindErrorHandlers(); bindRetryHandlers(); + installLocations(); } /** 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 6296619301..10cd1eeb54 100644 --- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java @@ -139,6 +139,7 @@ import com.google.common.base.Functions; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -759,7 +760,10 @@ public class RestAnnotationProcessor { return null; } - //TODO: change to LoadingCache and move this logic to the CacheLoader. + private final static TypeLiteral> uriSupplierLiteral = new TypeLiteral>() { + }; + + // TODO: change to LoadingCache and move this logic to the CacheLoader. public static URI getEndpointFor(Method method, Object[] args, Injector injector) throws ExecutionException { URI endpoint = getEndpointInParametersOrNull(method, args, injector); if (endpoint == null) { @@ -771,18 +775,22 @@ public class RestAnnotationProcessor { } else { throw new IllegalStateException("no annotations on class or method: " + method); } - endpoint = injector.getInstance(Key.get(URI.class, annotation.value())); + endpoint = injector.getInstance(Key.get(uriSupplierLiteral, annotation.value())).get(); } - return addHostIfMissing(endpoint, injector.getInstance(Key.get(URI.class, org.jclouds.location.Provider.class))); + URI providerEndpoint = injector.getInstance(Key.get(uriSupplierLiteral, org.jclouds.location.Provider.class)) + .get(); + return addHostIfMissing(endpoint, providerEndpoint); } public static URI addHostIfMissing(URI original, URI withHost) { - checkNotNull(withHost,"URI witHost cannot be null"); - checkArgument(withHost.getHost()!=null, "URI withHost must have host:"+withHost); + checkNotNull(withHost, "URI witHost cannot be null"); + checkArgument(withHost.getHost() != null, "URI withHost must have host:" + withHost); - if(original == null) return null; - if (original.getHost() != null) return original; - return withHost.resolve(original); + if (original == null) + return null; + if (original.getHost() != null) + return original; + return withHost.resolve(original); } public static final TypeLiteral> futureBooleanLiteral = new TypeLiteral>() { diff --git a/core/src/main/java/org/jclouds/rest/suppliers/MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.java b/core/src/main/java/org/jclouds/rest/suppliers/MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.java index 6fa91dfac7..5751b1dda6 100644 --- a/core/src/main/java/org/jclouds/rest/suppliers/MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.java +++ b/core/src/main/java/org/jclouds/rest/suppliers/MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.java @@ -47,6 +47,11 @@ public class MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier imp private final Supplier delegate; private final long seconds; + public static MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier create( + AtomicReference authException, long seconds, Supplier delegate) { + return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier(authException, seconds, delegate); + } + public MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier( AtomicReference authException, long seconds, Supplier delegate) { this.delegate = memoizeWithExpirationOnAbsoluteInterval(new RetryOnTimeOutExceptionSupplier( diff --git a/core/src/main/java/org/jclouds/rest/suppliers/URIFromStringSupplier.java b/core/src/main/java/org/jclouds/rest/suppliers/URIFromStringSupplier.java new file mode 100644 index 0000000000..617a5780ab --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/suppliers/URIFromStringSupplier.java @@ -0,0 +1,43 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.suppliers; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.URI; + +import javax.inject.Inject; + +import com.google.common.base.Supplier; + +public class URIFromStringSupplier implements Supplier { + + private final URI endpoint; + + @Inject + protected URIFromStringSupplier(String uri) { + this.endpoint = URI.create(checkNotNull(uri, "uri")); + } + + @Override + public URI get() { + return endpoint; + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java b/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java new file mode 100644 index 0000000000..74b8b1209e --- /dev/null +++ b/core/src/main/java/org/jclouds/suppliers/SupplyKeyMatchingValueOrNull.java @@ -0,0 +1,64 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.suppliers; + +import java.util.Map; + +import javax.annotation.Resource; + +import org.jclouds.logging.Logger; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; + +/** + * Allows you to lazy discover a key by value. This is useful for example in service discovery, + * where you need to see what the "current" service name is based on a map of service names to + * endpoints.

note

take care to memoize this using {@link Suppliers#memoize(Supplier)} + * + * @author Adrian Cole + */ +public class SupplyKeyMatchingValueOrNull implements Supplier { + @Resource + protected Logger logger = Logger.NULL; + + private final Supplier>> supplier; + private final Supplier valueSupplier; + + public SupplyKeyMatchingValueOrNull(Supplier>> supplier, Supplier valueSupplier) { + this.valueSupplier = valueSupplier; + this.supplier = supplier; + } + + @Override + public K get() { + V uri = valueSupplier.get(); + // eagerly get all the values, so we can see which is default + Map map = Maps.transformValues(supplier.get(), Suppliers. supplierFunction()); + K region = ImmutableBiMap.copyOf(map).inverse().get(uri); + if (region == null && map.size() > 0) { + logger.warn("failed to find key for value %s in %s; choosing first: %s", uri, map, region); + region = Iterables.get(map.keySet(), 0); + } + return region; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/util/Maps2.java b/core/src/main/java/org/jclouds/util/Maps2.java index 752321b91e..8150d8e24e 100644 --- a/core/src/main/java/org/jclouds/util/Maps2.java +++ b/core/src/main/java/org/jclouds/util/Maps2.java @@ -41,6 +41,19 @@ import com.google.common.collect.Multimap; * @author Adrian Cole */ public class Maps2 { + public static Function, Set> keySetFunction() { + return new Function, Set>() { + + @Override + public Set apply(Map arg0) { + return arg0.keySet(); + } + + public String toString() { + return "keySet()"; + } + }; + } public static Map convertUnsafe(Multimap in) { LinkedHashMap out = Maps.newLinkedHashMap(); diff --git a/core/src/main/java/org/jclouds/util/Suppliers2.java b/core/src/main/java/org/jclouds/util/Suppliers2.java index bbfa6a187e..deeb8c8df1 100644 --- a/core/src/main/java/org/jclouds/util/Suppliers2.java +++ b/core/src/main/java/org/jclouds/util/Suppliers2.java @@ -26,8 +26,10 @@ import java.io.Serializable; import java.util.concurrent.TimeUnit; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.io.OutputSupplier; /** @@ -36,6 +38,21 @@ import com.google.common.io.OutputSupplier; */ public class Suppliers2 { + public static Function> ofInstanceFunction() { + return new Function>(){ + + @Override + public Supplier apply(X arg0) { + return Suppliers.ofInstance(arg0); + } + + @Override + public String toString(){ + return "Suppliers.ofInstance()"; + } + }; + } + /** * converts an {@link OutputStream} to an {@link OutputSupplier} * @@ -52,9 +69,11 @@ public class Suppliers2 { /** * See Supplier.memoizeWithExpiration. * - * Difference between this impl and v11.0 is that we fix http://code.google.com/p/guava-libraries/issues/detail?id=857. + * Difference between this impl and v11.0 is that we fix + * http://code.google.com/p/guava-libraries/issues/detail?id=857. */ - public static Supplier memoizeWithExpirationOnAbsoluteInterval(Supplier delegate, long duration, TimeUnit unit) { + public static Supplier memoizeWithExpirationOnAbsoluteInterval(Supplier delegate, long duration, + TimeUnit unit) { return new ExpiringMemoizingSupplier(delegate, duration, unit); } @@ -85,16 +104,17 @@ public class Suppliers2 { if (nanos == 0 || now - nanos >= 0) { synchronized (this) { if (nanos == expirationNanos) { // recheck for lost race - - // Set value to null prior to retrieving new val, so old and new are not held in memory simultaneously + + // Set value to null prior to retrieving new val, so old and new are not held in + // memory simultaneously value = null; - + T t = delegate.get(); value = t; // Update now so that, if call was expensive, we keep value for the full duration now = System.nanoTime(); - + nanos = now + durationNanos; // In the very unlikely event that nanos is 0, set it to 1; // no one will notice 1 ns of tardiness. diff --git a/core/src/main/java/org/jclouds/util/Throwables2.java b/core/src/main/java/org/jclouds/util/Throwables2.java index 00fa94d2f4..a3424cf53b 100644 --- a/core/src/main/java/org/jclouds/util/Throwables2.java +++ b/core/src/main/java/org/jclouds/util/Throwables2.java @@ -25,11 +25,13 @@ import static com.google.common.collect.Iterables.find; import java.util.NoSuchElementException; +import org.jclouds.concurrent.TransformParallelException; import org.jclouds.http.HttpResponseException; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.InsufficientResourcesException; import org.jclouds.rest.ResourceNotFoundException; +import com.google.common.base.Predicate; import com.google.common.base.Throwables; import com.google.inject.CreationException; import com.google.inject.ProvisionException; @@ -42,10 +44,26 @@ import com.google.inject.spi.Message; */ public class Throwables2 { + public static Predicate containsThrowable(final Class throwableType) { + return new Predicate() { + + @Override + public boolean apply(Throwable input) { + return getFirstThrowableOfType(input, throwableType) != null; + } + + public String toString() { + return "containsThrowable()"; + } + }; + } + @SuppressWarnings("unchecked") public static T getFirstThrowableOfType(Throwable from, Class clazz) { if (from instanceof ProvisionException) return getFirstThrowableOfType(ProvisionException.class.cast(from), clazz); + else if (from instanceof TransformParallelException) + return getFirstThrowableOfType(TransformParallelException.class.cast(from), clazz); else if (from instanceof CreationException) return getFirstThrowableOfType(CreationException.class.cast(from), clazz); try { @@ -55,12 +73,23 @@ public class Throwables2 { } } + public static T getFirstThrowableOfType(TransformParallelException e, Class clazz) { + for (Exception exception : e.getFromToException().values()) { + T cause = getFirstThrowableOfType(exception, clazz); + if (cause != null) + return cause; + } + return null; + } + public static T getFirstThrowableOfType(ProvisionException e, Class clazz) { for (Message message : e.getErrorMessages()) { if (message.getCause() != null) { T cause = getFirstThrowableOfType(message.getCause(), clazz); if (cause instanceof ProvisionException) return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz); + else if (cause instanceof TransformParallelException) + return getFirstThrowableOfType(TransformParallelException.class.cast(cause), clazz); else if (cause instanceof CreationException) return getFirstThrowableOfType(CreationException.class.cast(cause), clazz); return cause; @@ -75,6 +104,8 @@ public class Throwables2 { T cause = getFirstThrowableOfType(message.getCause(), clazz); if (cause instanceof ProvisionException) return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz); + else if (cause instanceof TransformParallelException) + return getFirstThrowableOfType(TransformParallelException.class.cast(cause), clazz); else if (cause instanceof CreationException) return getFirstThrowableOfType(CreationException.class.cast(cause), clazz); return cause; @@ -99,9 +130,10 @@ public class Throwables2 { return (Exception) throwable; } } - for (Class propagatableExceptionType : new Class[] { IllegalStateException.class, AssertionError.class, - UnsupportedOperationException.class, IllegalArgumentException.class, AuthorizationException.class, - ResourceNotFoundException.class, InsufficientResourcesException.class, HttpResponseException.class }) { + for (Class propagatableExceptionType : new Class[] { IllegalStateException.class, + AssertionError.class, UnsupportedOperationException.class, IllegalArgumentException.class, + AuthorizationException.class, ResourceNotFoundException.class, InsufficientResourcesException.class, + HttpResponseException.class }) { Throwable throwable = getFirstThrowableOfType(exception, propagatableExceptionType); if (throwable != null) { if (throwable instanceof AssertionError) diff --git a/core/src/test/java/org/jclouds/concurrent/FutureIterablesPerformanceTest.java b/core/src/test/java/org/jclouds/concurrent/FutureIterablesPerformanceTest.java new file mode 100644 index 0000000000..27b24218cc --- /dev/null +++ b/core/src/test/java/org/jclouds/concurrent/FutureIterablesPerformanceTest.java @@ -0,0 +1,249 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.concurrent; + +import static com.google.common.base.Throwables.propagate; +import static com.google.common.collect.Maps.newHashMap; +import static java.util.concurrent.Executors.newCachedThreadPool; +import static org.jclouds.concurrent.FutureIterables.awaitCompletion; +import static org.testng.Assert.assertEquals; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import org.jclouds.logging.Logger; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; + +/** + * Tests behavior of FutureIterables + * + * @author Adrian Cole + */ +@Test(groups = "performance", enabled = false, sequential = true, testName = "FutureIterablesPerformanceTest") +public class FutureIterablesPerformanceTest { + ExecutorService ioFunctionExecutor = newCachedThreadPool(); + + @Test(enabled = false) + public void testMakeListenableDoesntSerializeFutures() throws InterruptedException, ExecutionException { + long expectedMax = IO_DURATION; + long expectedMin = IO_DURATION; + long expectedOverhead = COUNT + FUDGE; + + ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); + + long start = System.currentTimeMillis(); + Map> responses = runCallables(chainExecutor); + checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); + } + + @Test(enabled = false) + public void testAwaitCompletionUsingSameThreadExecutorDoesntSerializeFutures() throws InterruptedException, + ExecutionException { + long expectedMax = IO_DURATION; + long expectedMin = IO_DURATION; + long expectedOverhead = COUNT + FUDGE; + + ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); + + long start = System.currentTimeMillis(); + Map> responses = runCallables(chainExecutor); + Map exceptions = awaitCompletion(responses, MoreExecutors.sameThreadExecutor(), null, + Logger.CONSOLE, "test same thread"); + assertEquals(exceptions.size(), 0); + checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); + } + + @Test(enabled = false) + public void whenCachedThreadPoolIsUsedForChainAndListenerMaxDurationIsSumOfCallableAndListener() + throws InterruptedException, ExecutionException { + long expectedMax = IO_DURATION + LISTENER_DURATION; + long expectedMin = IO_DURATION + LISTENER_DURATION; + long expectedOverhead = COUNT * 4 + FUDGE; + + ExecutorService userthreads = newCachedThreadPool(); + try { + ExecutorService chainExecutor = userthreads; + ExecutorService listenerExecutor = userthreads; + + checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); + } finally { + userthreads.shutdownNow(); + } + } + + @Test(enabled = false) + public void whenCachedThreadPoolIsUsedForChainButSameThreadForListenerMaxDurationIsSumOfCallableAndListener() + throws InterruptedException, ExecutionException { + long expectedMax = IO_DURATION + LISTENER_DURATION; + long expectedMin = IO_DURATION + LISTENER_DURATION; + long expectedOverhead = COUNT + FUDGE; + + ExecutorService userthreads = newCachedThreadPool(); + try { + ExecutorService chainExecutor = userthreads; + ExecutorService listenerExecutor = MoreExecutors.sameThreadExecutor(); + + checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); + } finally { + userthreads.shutdownNow(); + } + } + + @Test(enabled = false) + public void whenSameThreadIsUsedForChainButCachedThreadPoolForListenerMaxDurationIsIOAndSumOfAllListeners() + throws InterruptedException, ExecutionException { + long expectedMax = IO_DURATION + (LISTENER_DURATION * COUNT); + long expectedMin = IO_DURATION + LISTENER_DURATION; + long expectedOverhead = COUNT + FUDGE; + + ExecutorService userthreads = newCachedThreadPool(); + try { + ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); + ExecutorService listenerExecutor = userthreads; + + checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); + } finally { + userthreads.shutdownNow(); + } + } + + @Test(enabled = false) + public void whenSameThreadIsUsedForChainAndListenerMaxDurationIsIOAndSumOfAllListeners() + throws InterruptedException, ExecutionException { + + long expectedMax = IO_DURATION + (LISTENER_DURATION * COUNT); + long expectedMin = IO_DURATION + LISTENER_DURATION; + long expectedOverhead = COUNT + FUDGE; + + ExecutorService userthreads = newCachedThreadPool(); + try { + ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); + ExecutorService listenerExecutor = MoreExecutors.sameThreadExecutor(); + + checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); + } finally { + userthreads.shutdownNow(); + } + } + + public static final int FUDGE = 5; + public static final int COUNT = 100; + public static final int IO_DURATION = 50; + public static final int LISTENER_DURATION = 100; + + private void checkThresholdsUsingCompose(long expectedMin, long expectedMax, long expectedOverhead, + ExecutorService chainExecutor, final ExecutorService listenerExecutor) { + long start = System.currentTimeMillis(); + Map> responses = newHashMap(); + for (int i = 0; i < COUNT; i++) + responses.put(i + "", org.jclouds.concurrent.Futures.compose(org.jclouds.concurrent.Futures.makeListenable( + simultateIO(), chainExecutor), new Function() { + + @Override + public Long apply(Long from) { + try { + Thread.sleep(LISTENER_DURATION); + } catch (InterruptedException e) { + propagate(e); + } + return System.currentTimeMillis(); + } + + }, listenerExecutor)); + checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); + } + + private Map> runCallables(ExecutorService chainExecutor) { + Map> responses = newHashMap(); + for (int i = 0; i < COUNT; i++) + responses.put(i + "", org.jclouds.concurrent.Futures.makeListenable(simultateIO(), chainExecutor)); + return responses; + } + + private Future simultateIO() { + return ioFunctionExecutor.submit(new Callable() { + + @Override + public Long call() throws Exception { + Thread.sleep(IO_DURATION); + return System.currentTimeMillis(); + } + + }); + } + + public static long getMaxIn(Map> responses) { + Iterable collection = Iterables.transform(responses.values(), new Function, Long>() { + + @Override + public Long apply(Future from) { + try { + return from.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return null; + } + + }); + long time = Collections.max(Sets.newHashSet(collection)); + return time; + } + + public static long getMinIn(Map> responses) { + Iterable collection = Iterables.transform(responses.values(), new Function, Long>() { + + @Override + public Long apply(Future from) { + try { + return from.get(); + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return null; + } + + }); + long time = Collections.min(Sets.newHashSet(collection)); + return time; + } + + private static void checkTimeThresholds(long expectedMin, long expectedMax, long expectedOverhead, long start, + Map> responses) { + long time = getMaxIn(responses) - start; + assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expectedMax %d, max %d", + expectedMax, time); + + time = getMinIn(responses) - start; + assert time >= expectedMin && time < expectedMin + expectedOverhead : String.format("expectedMin %d, min %d", + expectedMin, time); + + time = getMaxIn(responses) - start; + assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expectedMax %d, max %d", + expectedMax, time); + } +} diff --git a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java index 9fc3cde3f8..0601ede17b 100644 --- a/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java +++ b/core/src/test/java/org/jclouds/concurrent/FutureIterablesTest.java @@ -18,232 +18,66 @@ */ package org.jclouds.concurrent; -import static com.google.common.base.Throwables.propagate; -import static com.google.common.collect.Maps.newHashMap; -import static java.util.concurrent.Executors.newCachedThreadPool; -import static org.jclouds.concurrent.FutureIterables.awaitCompletion; +import static org.jclouds.concurrent.FutureIterables.transformParallel; import static org.testng.Assert.assertEquals; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; import org.testng.annotations.Test; import com.google.common.base.Function; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; +import com.google.common.collect.ImmutableSet; /** * Tests behavior of FutureIterables * * @author Adrian Cole */ -@Test(groups = "performance", enabled = false, sequential = true, testName = "FutureIterablesTest") +@Test(groups = "unit", singleThreaded = true, testName = "FutureIterablesTest") public class FutureIterablesTest { - ExecutorService ioFunctionExecutor = newCachedThreadPool(); - @Test(enabled = false) - public void testMakeListenableDoesntSerializeFutures() throws InterruptedException, ExecutionException { - long expectedMax = IO_DURATION; - long expectedMin = IO_DURATION; - long expectedOverhead = COUNT + FUDGE; + public void testAuthorizationExceptionPropagatesAndOnlyTriesOncePerElement() { + final AtomicInteger counter = new AtomicInteger(); - ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); - - long start = System.currentTimeMillis(); - Map> responses = runCallables(chainExecutor); - checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); - } - - @Test(enabled = false) - public void testAwaitCompletionUsingSameThreadExecutorDoesntSerializeFutures() throws InterruptedException, - ExecutionException { - long expectedMax = IO_DURATION; - long expectedMin = IO_DURATION; - long expectedOverhead = COUNT + FUDGE; - - ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); - - long start = System.currentTimeMillis(); - Map> responses = runCallables(chainExecutor); - Map exceptions = awaitCompletion(responses, MoreExecutors.sameThreadExecutor(), null, - Logger.CONSOLE, "test same thread"); - assertEquals(exceptions.size(), 0); - checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); - } - - @Test(enabled = false) - public void whenCachedThreadPoolIsUsedForChainAndListenerMaxDurationIsSumOfCallableAndListener() - throws InterruptedException, ExecutionException { - long expectedMax = IO_DURATION + LISTENER_DURATION; - long expectedMin = IO_DURATION + LISTENER_DURATION; - long expectedOverhead = COUNT * 4 + FUDGE; - - ExecutorService userthreads = newCachedThreadPool(); try { - ExecutorService chainExecutor = userthreads; - ExecutorService listenerExecutor = userthreads; - - checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); - } finally { - userthreads.shutdownNow(); - } - } - - @Test(enabled = false) - public void whenCachedThreadPoolIsUsedForChainButSameThreadForListenerMaxDurationIsSumOfCallableAndListener() - throws InterruptedException, ExecutionException { - long expectedMax = IO_DURATION + LISTENER_DURATION; - long expectedMin = IO_DURATION + LISTENER_DURATION; - long expectedOverhead = COUNT + FUDGE; - - ExecutorService userthreads = newCachedThreadPool(); - try { - ExecutorService chainExecutor = userthreads; - ExecutorService listenerExecutor = MoreExecutors.sameThreadExecutor(); - - checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); - } finally { - userthreads.shutdownNow(); - } - } - - @Test(enabled = false) - public void whenSameThreadIsUsedForChainButCachedThreadPoolForListenerMaxDurationIsIOAndSumOfAllListeners() - throws InterruptedException, ExecutionException { - long expectedMax = IO_DURATION + (LISTENER_DURATION * COUNT); - long expectedMin = IO_DURATION + LISTENER_DURATION; - long expectedOverhead = COUNT + FUDGE; - - ExecutorService userthreads = newCachedThreadPool(); - try { - ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); - ExecutorService listenerExecutor = userthreads; - - checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); - } finally { - userthreads.shutdownNow(); - } - } - - @Test(enabled = false) - public void whenSameThreadIsUsedForChainAndListenerMaxDurationIsIOAndSumOfAllListeners() - throws InterruptedException, ExecutionException { - - long expectedMax = IO_DURATION + (LISTENER_DURATION * COUNT); - long expectedMin = IO_DURATION + LISTENER_DURATION; - long expectedOverhead = COUNT + FUDGE; - - ExecutorService userthreads = newCachedThreadPool(); - try { - ExecutorService chainExecutor = MoreExecutors.sameThreadExecutor(); - ExecutorService listenerExecutor = MoreExecutors.sameThreadExecutor(); - - checkThresholdsUsingCompose(expectedMin, expectedMax, expectedOverhead, chainExecutor, listenerExecutor); - } finally { - userthreads.shutdownNow(); - } - } - - public static final int FUDGE = 5; - public static final int COUNT = 100; - public static final int IO_DURATION = 50; - public static final int LISTENER_DURATION = 100; - - private void checkThresholdsUsingCompose(long expectedMin, long expectedMax, long expectedOverhead, - ExecutorService chainExecutor, final ExecutorService listenerExecutor) { - long start = System.currentTimeMillis(); - Map> responses = newHashMap(); - for (int i = 0; i < COUNT; i++) - responses.put(i + "", org.jclouds.concurrent.Futures.compose(org.jclouds.concurrent.Futures.makeListenable( - simultateIO(), chainExecutor), new Function() { + transformParallel(ImmutableSet.of("hello", "goodbye"), new Function>() { @Override - public Long apply(Long from) { - try { - Thread.sleep(LISTENER_DURATION); - } catch (InterruptedException e) { - propagate(e); - } - return System.currentTimeMillis(); + public Future apply(String input) { + counter.incrementAndGet(); + return com.google.common.util.concurrent.Futures.immediateFailedFuture(new AuthorizationException()); } - }, listenerExecutor)); - checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses); + }, MoreExecutors.sameThreadExecutor(), null, Logger.CONSOLE, ""); + assert false; + } catch (AuthorizationException e) { + assertEquals(counter.get(), 2); + } + } + + public void testNormalExceptionPropagatesAsTransformParallelExceptionAndTries5XPerElement() { + final AtomicInteger counter = new AtomicInteger(); - private Map> runCallables(ExecutorService chainExecutor) { - Map> responses = newHashMap(); - for (int i = 0; i < COUNT; i++) - responses.put(i + "", org.jclouds.concurrent.Futures.makeListenable(simultateIO(), chainExecutor)); - return responses; - } + try { + transformParallel(ImmutableSet.of("hello", "goodbye"), new Function>() { - private Future simultateIO() { - return ioFunctionExecutor.submit(new Callable() { - - @Override - public Long call() throws Exception { - Thread.sleep(IO_DURATION); - return System.currentTimeMillis(); - } - - }); - } - - public static long getMaxIn(Map> responses) { - Iterable collection = Iterables.transform(responses.values(), new Function, Long>() { - - @Override - public Long apply(Future from) { - try { - return from.get(); - } catch (InterruptedException e) { - } catch (ExecutionException e) { + @Override + public Future apply(String input) { + counter.incrementAndGet(); + return com.google.common.util.concurrent.Futures.immediateFailedFuture(new RuntimeException()); } - return null; - } - }); - long time = Collections.max(Sets.newHashSet(collection)); - return time; + }, MoreExecutors.sameThreadExecutor(), null, Logger.CONSOLE, ""); + assert false; + } catch (TransformParallelException e) { + assertEquals(e.getFromToException().size(), 2); + assertEquals(counter.get(), 10); + } + } - public static long getMinIn(Map> responses) { - Iterable collection = Iterables.transform(responses.values(), new Function, Long>() { - - @Override - public Long apply(Future from) { - try { - return from.get(); - } catch (InterruptedException e) { - } catch (ExecutionException e) { - } - return null; - } - - }); - long time = Collections.min(Sets.newHashSet(collection)); - return time; - } - - private static void checkTimeThresholds(long expectedMin, long expectedMax, long expectedOverhead, long start, - Map> responses) { - long time = getMaxIn(responses) - start; - assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expectedMax %d, max %d", - expectedMax, time); - - time = getMinIn(responses) - start; - assert time >= expectedMin && time < expectedMin + expectedOverhead : String.format("expectedMin %d, min %d", - expectedMin, time); - - time = getMaxIn(responses) - start; - assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expectedMax %d, max %d", - expectedMax, time); - } } diff --git a/core/src/test/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaPropertiesTest.java b/core/src/test/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaPropertiesTest.java index 30cf08e40f..6f712d1e82 100644 --- a/core/src/test/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaPropertiesTest.java +++ b/core/src/test/java/org/jclouds/location/config/ProvideIso3166CodesByLocationIdViaPropertiesTest.java @@ -23,10 +23,13 @@ import static org.testng.Assert.assertEquals; import java.util.Map; import java.util.Set; +import org.jclouds.location.suppliers.LocationIdToIso3166CodesSupplier; +import org.jclouds.util.Suppliers2; import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; @@ -42,14 +45,14 @@ import com.google.inject.Provides; public class ProvideIso3166CodesByLocationIdViaPropertiesTest { public void testEmptyWhenNoLocationsBound() { - ProvideIso3166CodesByLocationIdViaProperties fn = createWithValue(ImmutableMap. of()); + LocationIdToIso3166CodesSupplier fn = createWithValue(ImmutableMap. of()); assertEquals(fn.get(), ImmutableMap.> of()); } public void testEmptyWhenRegionsAndZonesBoundButNoIsoCodes() { - ProvideIso3166CodesByLocationIdViaProperties fn = createWithValue(ImmutableMap. of( + LocationIdToIso3166CodesSupplier fn = createWithValue(ImmutableMap. of( "jclouds.regions", "us-east", "jclouds.zones", "us-easta")); assertEquals(fn.get(), ImmutableMap.> of()); @@ -57,20 +60,18 @@ public class ProvideIso3166CodesByLocationIdViaPropertiesTest { public void testIsoCodesWhenRegionsAndZonesBoundWithIsoCodes() { - ProvideIso3166CodesByLocationIdViaProperties fn = createWithValue(ImmutableMap. of( + LocationIdToIso3166CodesSupplier fn = createWithValue(ImmutableMap. of( "jclouds.regions", "us-east", "jclouds.region.us-east.iso3166-codes", "US", "jclouds.zones", "us-easta", "jclouds.zone.us-easta.iso3166-codes", "US-CA")); - assertEquals( - fn.get(), - ImmutableMap.> of("us-east", ImmutableSet.of("US"), "us-easta", - ImmutableSet.of("US-CA"))); + assertEquals(Maps.transformValues(fn.get(), Suppliers.> supplierFunction()), ImmutableMap + .> of("us-east", ImmutableSet.of("US"), "us-easta", ImmutableSet.of("US-CA"))); } // - private ProvideIso3166CodesByLocationIdViaProperties createWithValue(final ImmutableMap value) { - ProvideIso3166CodesByLocationIdViaProperties fn = Guice.createInjector(new AbstractModule() { + private LocationIdToIso3166CodesSupplier createWithValue(final ImmutableMap value) { + LocationIdToIso3166CodesSupplier fn = Guice.createInjector(new AbstractModule() { @SuppressWarnings("unused") @Provides Function, Map> provide() { @@ -87,7 +88,7 @@ public class ProvideIso3166CodesByLocationIdViaPropertiesTest { protected void configure() { } - }).getInstance(ProvideIso3166CodesByLocationIdViaProperties.class); + }).getInstance(LocationIdToIso3166CodesSupplier.class); return fn; } diff --git a/core/src/test/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNullTest.java b/core/src/test/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNullTest.java index 8dc925186f..003999b00a 100644 --- a/core/src/test/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNullTest.java +++ b/core/src/test/java/org/jclouds/location/functions/RegionToEndpointOrProviderIfNullTest.java @@ -22,9 +22,12 @@ import static org.testng.Assert.assertEquals; import java.io.File; import java.net.URI; +import java.util.Map; import org.testng.annotations.Test; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; /** @@ -37,33 +40,34 @@ public class RegionToEndpointOrProviderIfNullTest { @Test public void testWhenFindsRegion() throws SecurityException, NoSuchMethodException { - RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", URI.create("http://leader"), - ImmutableMap.of("1", URI.create("http://1"))); + RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", Suppliers.ofInstance(URI + .create("http://leader")), Suppliers.>>ofInstance(ImmutableMap.of("1", Suppliers.ofInstance(URI.create("http://1"))))); assertEquals(fn.apply("1"), URI.create("http://1")); } public void testNullReturnsProvider() { - RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", URI.create("http://leader"), - ImmutableMap.of("1", URI.create("http://1"))); + RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", Suppliers.ofInstance(URI + .create("http://leader")), Suppliers.>>ofInstance(ImmutableMap.of("1", Suppliers.ofInstance(URI.create("http://1"))))); assertEquals(fn.apply("leader"), URI.create("http://leader")); } @Test(expectedExceptions = IllegalArgumentException.class) public void testMustBeString() { - RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", URI.create("http://leader"), - ImmutableMap.of("1", URI.create("http://1"))); + RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", Suppliers.ofInstance(URI + .create("http://leader")), Suppliers.>>ofInstance(ImmutableMap.of("1", Suppliers.ofInstance(URI.create("http://1"))))); fn.apply(new File("foo")); } @Test(expectedExceptions = IllegalArgumentException.class) public void testMustBeInRegionMapIfSpecified() { - RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", URI.create("http://leader"), - ImmutableMap.of("1", URI.create("http://1"))); + RegionToEndpointOrProviderIfNull fn = new RegionToEndpointOrProviderIfNull("leader", Suppliers.ofInstance(URI + .create("http://leader")), Suppliers.>>ofInstance(ImmutableMap.of("1", Suppliers.ofInstance(URI.create("http://1"))))); fn.apply("2"); } public void testOkIfNoRegionMappings() { - new RegionToEndpointOrProviderIfNull("leader", URI.create("http://leader"), ImmutableMap. of()); + new RegionToEndpointOrProviderIfNull("leader", Suppliers.ofInstance(URI.create("http://leader")), Suppliers + .>> ofInstance(ImmutableMap.> of())); } } diff --git a/core/src/test/java/org/jclouds/location/functions/ZoneToEndpointTest.java b/core/src/test/java/org/jclouds/location/functions/ZoneToEndpointTest.java index a90d258db4..6899c14d0b 100644 --- a/core/src/test/java/org/jclouds/location/functions/ZoneToEndpointTest.java +++ b/core/src/test/java/org/jclouds/location/functions/ZoneToEndpointTest.java @@ -22,9 +22,12 @@ import static org.testng.Assert.assertEquals; import java.io.File; import java.net.URI; +import java.util.Map; import org.testng.annotations.Test; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; /** @@ -36,25 +39,30 @@ import com.google.common.collect.ImmutableMap; public class ZoneToEndpointTest { @Test - public void testCorrect() throws SecurityException, NoSuchMethodException { - ZoneToEndpoint fn = new ZoneToEndpoint(ImmutableMap.of("1", URI.create("http://1"))); + public void testCorrect() { + ZoneToEndpoint fn = new ZoneToEndpoint(Suppliers.>> ofInstance(ImmutableMap.of("1", + Suppliers.ofInstance(URI.create("http://1"))))); assertEquals(fn.apply("1"), URI.create("http://1")); } @Test(expectedExceptions = IllegalArgumentException.class) public void testMustBeString() { - ZoneToEndpoint fn = new ZoneToEndpoint(ImmutableMap.of("1", URI.create("http://1"))); + ZoneToEndpoint fn = new ZoneToEndpoint(Suppliers.>> ofInstance(ImmutableMap.of("1", + Suppliers.ofInstance(URI.create("http://1"))))); fn.apply(new File("foo")); } - @Test(expectedExceptions = IllegalArgumentException.class) + @Test(expectedExceptions = IllegalStateException.class) public void testMustHaveEndpoints() { - new ZoneToEndpoint(ImmutableMap. of()); + ZoneToEndpoint fn = new ZoneToEndpoint(Suppliers.>> ofInstance(ImmutableMap + .> of())); + fn.apply("1"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullIsIllegal() { - ZoneToEndpoint fn = new ZoneToEndpoint(ImmutableMap.of("1", URI.create("http://1"))); + ZoneToEndpoint fn = new ZoneToEndpoint(Suppliers.>> ofInstance(ImmutableMap.of("1", + Suppliers.ofInstance(URI.create("http://1"))))); fn.apply(null); } } diff --git a/core/src/test/java/org/jclouds/location/suppliers/JustProviderTest.java b/core/src/test/java/org/jclouds/location/suppliers/all/JustProviderTest.java similarity index 94% rename from core/src/test/java/org/jclouds/location/suppliers/JustProviderTest.java rename to core/src/test/java/org/jclouds/location/suppliers/all/JustProviderTest.java index 35c5d75df8..dc7b1e8837 100644 --- a/core/src/test/java/org/jclouds/location/suppliers/JustProviderTest.java +++ b/core/src/test/java/org/jclouds/location/suppliers/all/JustProviderTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.all; import static org.testng.Assert.assertEquals; @@ -24,6 +24,7 @@ import java.net.URI; import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationScope; +import org.jclouds.location.suppliers.all.JustProvider; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; diff --git a/core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java b/core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java similarity index 79% rename from core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java rename to core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java index 960ab9d507..e398f1088b 100644 --- a/core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java +++ b/core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.implicit; import static org.testng.Assert.assertEquals; @@ -40,55 +40,55 @@ import com.google.common.collect.ImmutableSet; @Test(groups = "unit", testName = "OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest") public class OnlyLocationOrFirstRegionOptionallyMatchingRegionIdTest { Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("servo").description("http://servo") - .build(); + .build(); Location region = new LocationBuilder().scope(LocationScope.REGION).id("servo-r1").description("http://r1.servo") - .parent(provider).build(); + .parent(provider).build(); Location region2 = new LocationBuilder().scope(LocationScope.REGION).id("servo-r2").description("http://r2.servo") - .parent(provider).build(); + .parent(provider).build(); Location zone = new LocationBuilder().scope(LocationScope.ZONE).id("servo-z").description("http://z.r.servo") - .parent(region).build(); + .parent(region).build(); @Test public void testDidntMatchRegionIdThrowsNSEEWithReasonableMessage() { Supplier> supplier = Suppliers.> ofInstance(ImmutableSet - . of(provider, region, region2, zone)); + . of(provider, region, region2, zone)); OnlyLocationOrFirstRegionOptionallyMatchingRegionId fn = new OnlyLocationOrFirstRegionOptionallyMatchingRegionId( - "foo", supplier); + Suppliers.ofInstance("foo"), supplier); try { fn.get(); assert false; } catch (NoSuchElementException e) { assertEquals( - e.getMessage(), - "couldn't find region matching isRegionAndIdEqualsOrIsZoneParentIdEquals(foo) in [servo:PROVIDER, servo-r1:REGION, servo-r2:REGION, servo-z:ZONE]"); + e.getMessage(), + "couldn't find region matching isRegionAndIdEqualsOrIsZoneParentIdEquals(foo) in [servo:PROVIDER, servo-r1:REGION, servo-r2:REGION, servo-z:ZONE]"); } } @Test public void testNoRegionUsesProvider() { Supplier> supplier = Suppliers.> ofInstance(ImmutableSet - . of(provider)); + . of(provider)); OnlyLocationOrFirstRegionOptionallyMatchingRegionId fn = new OnlyLocationOrFirstRegionOptionallyMatchingRegionId( - null, supplier); + Suppliers.ofInstance(null), supplier); assertEquals(fn.get(), provider); } @Test public void testFirstRegion() { Supplier> supplier = Suppliers.> ofInstance(ImmutableSet - . of(provider, region, region2, zone)); + . of(provider, region, region2, zone)); OnlyLocationOrFirstRegionOptionallyMatchingRegionId fn = new OnlyLocationOrFirstRegionOptionallyMatchingRegionId( - null, supplier); + Suppliers.ofInstance(null), supplier); assertEquals(fn.get(), region); } @Test public void testFindRegion() { Supplier> supplier = Suppliers.> ofInstance(ImmutableSet - . of(provider, region, region2, zone)); + . of(provider, region, region2, zone)); OnlyLocationOrFirstRegionOptionallyMatchingRegionId fn = new OnlyLocationOrFirstRegionOptionallyMatchingRegionId( - region2.getId(), supplier); + Suppliers.ofInstance(region2.getId()), supplier); assertEquals(fn.get(), region2); } } diff --git a/core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZoneTest.java b/core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZoneTest.java similarity index 96% rename from core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZoneTest.java rename to core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZoneTest.java index 60edd13bfd..2928433fff 100644 --- a/core/src/test/java/org/jclouds/location/suppliers/OnlyLocationOrFirstZoneTest.java +++ b/core/src/test/java/org/jclouds/location/suppliers/implicit/OnlyLocationOrFirstZoneTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.jclouds.location.suppliers; +package org.jclouds.location.suppliers.implicit; import static org.testng.Assert.assertEquals; @@ -26,6 +26,7 @@ import java.util.Set; import org.jclouds.domain.Location; import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationScope; +import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone; import org.testng.annotations.Test; import com.google.common.base.Supplier; diff --git a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java index 51607f8104..47f66d698b 100644 --- a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java +++ b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java @@ -144,6 +144,8 @@ import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.base.Joiner; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; @@ -181,7 +183,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest { @Override protected void configure() { super.configure(); - bind(URI.class).annotatedWith(Localhost2.class).toInstance(URI.create("http://localhost:1111")); + bind(new TypeLiteral>() { + }).annotatedWith(Localhost2.class).toInstance( + Suppliers.ofInstance(URI.create("http://localhost:1111"))); bind(IOExceptionRetryHandler.class).toInstance(IOExceptionRetryHandler.NEVER_RETRY); } @@ -2436,7 +2440,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest { }).toInstance(ImmutableSet.of("foo")); bind(new TypeLiteral>() { }).annotatedWith(Names.named("bar")).toInstance(ImmutableSet.of("bar")); - bind(URI.class).annotatedWith(Localhost2.class).toInstance(URI.create("http://localhost:1111")); + bind(new TypeLiteral>() { + }).annotatedWith(Localhost2.class).toInstance( + Suppliers.ofInstance(URI.create("http://localhost:1111"))); } @SuppressWarnings("unused") diff --git a/core/src/test/java/org/jclouds/util/Throwables2Test.java b/core/src/test/java/org/jclouds/util/Throwables2Test.java index 20110ebb4a..68cfc3f117 100644 --- a/core/src/test/java/org/jclouds/util/Throwables2Test.java +++ b/core/src/test/java/org/jclouds/util/Throwables2Test.java @@ -26,8 +26,11 @@ import static org.testng.Assert.assertEquals; import java.io.IOException; import java.net.SocketException; +import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import org.jclouds.concurrent.TransformParallelException; import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpResponseException; import org.jclouds.rest.AuthorizationException; @@ -36,6 +39,7 @@ import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.inject.CreationException; import com.google.inject.ProvisionException; @@ -113,6 +117,38 @@ public class Throwables2Test { assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); } + @SuppressWarnings("unchecked") + public void testGetCauseTransformParallel() { + Exception aex = createMock(AuthorizationException.class); + TransformParallelException pex = new TransformParallelException((Map) ImmutableMap.of(), ImmutableMap.of("bad", + aex), "test"); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } + + @SuppressWarnings("unchecked") + public void testGetFirstThrowableOfTypeInnerTransformParallel() { + Exception aex = createMock(AuthorizationException.class); + TransformParallelException pex = new TransformParallelException((Map) ImmutableMap.of(), ImmutableMap.of("bad", + (Exception) new ExecutionException(aex)), "test"); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } + + @SuppressWarnings("unchecked") + public void testGetFirstThrowableOfTypeOuterTransformParallel() { + Exception aex = createMock(AuthorizationException.class); + TransformParallelException pex = new TransformParallelException((Map) ImmutableMap.of(), ImmutableMap.of("bad", + (Exception) aex), "test"); + assertEquals(getFirstThrowableOfType(new ExecutionException(pex), AuthorizationException.class), aex); + } + + @SuppressWarnings("unchecked") + public void testGetFirstThrowableOfTypeFailTransformParallel() { + Exception aex = createMock(TimeoutException.class); + TransformParallelException pex = new TransformParallelException((Map) ImmutableMap.of(), ImmutableMap.of("bad", + aex), "test"); + assertEquals(getFirstThrowableOfType(pex, AuthorizationException.class), null); + } + @Test public void testReturnExceptionThatsInList() throws Exception { Exception e = new TestException(); diff --git a/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BaseLoadBalancerServiceContextModule.java b/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BaseLoadBalancerServiceContextModule.java index 75a5a686f9..83ac70f8e5 100644 --- a/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BaseLoadBalancerServiceContextModule.java +++ b/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BaseLoadBalancerServiceContextModule.java @@ -18,22 +18,7 @@ */ package org.jclouds.loadbalancer.config; -import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; - -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -import javax.inject.Named; -import javax.inject.Singleton; - -import org.jclouds.collect.Memoized; -import org.jclouds.domain.Location; -import org.jclouds.rest.AuthorizationException; -import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; - -import com.google.common.base.Supplier; import com.google.inject.AbstractModule; -import com.google.inject.Provides; /** * @@ -41,25 +26,8 @@ import com.google.inject.Provides; */ public abstract class BaseLoadBalancerServiceContextModule extends AbstractModule { - protected AtomicReference authException = new AtomicReference(); - @Override protected void configure() { } - - @Provides - @Singleton - @Memoized - protected Supplier> supplyLocationCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, - final Supplier> locationSupplier) { - return new MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier>(authException, seconds, - new Supplier>() { - @Override - public Set get() { - return locationSupplier.get(); - } - }); - } - } \ No newline at end of file diff --git a/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BindLoadBalancerSuppliersByClass.java b/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BindLoadBalancerSuppliersByClass.java deleted file mode 100644 index 419612714a..0000000000 --- a/loadbalancer/src/main/java/org/jclouds/loadbalancer/config/BindLoadBalancerSuppliersByClass.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.loadbalancer.config; - -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.compute.domain.Hardware; -import org.jclouds.compute.domain.Image; -import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.OnlyLocationOrFirstRegionOptionallyMatchingRegionId; - -import com.google.common.base.Supplier; -import com.google.inject.AbstractModule; -import com.google.inject.Scopes; -import com.google.inject.TypeLiteral; - -/** - * @author Adrian Cole - */ -public abstract class BindLoadBalancerSuppliersByClass extends AbstractModule { - - @Override - protected void configure() { - bindLocationSupplier(defineLocationSupplier()); - bindDefaultLocationSupplier(defineDefaultLocationSupplier()); - } - - - protected Class>> defineLocationSupplier() { - return SupplierOfLocationSet.class; - } - - @Singleton - static class SupplierOfLocationSet implements Supplier> { - private final Set locations; - - @Inject - SupplierOfLocationSet(Set locations) { - this.locations = locations; - } - - @Override - public Set get() { - return locations; - } - - } - - protected Class> defineDefaultLocationSupplier() { - return OnlyLocationOrFirstRegionOptionallyMatchingRegionId.class; - } - - protected void bindImageSupplier(Class>> clazz) { - bind(new TypeLiteral>>() { - }).to(clazz).in(Scopes.SINGLETON); - } - - protected void bindLocationSupplier(Class>> clazz) { - bind(new TypeLiteral>>() { - }).to(clazz).in(Scopes.SINGLETON); - } - - protected void bindDefaultLocationSupplier(Class> clazz) { - bind(new TypeLiteral>() { - }).to(clazz).in(Scopes.SINGLETON); - } - - protected void bindHardwareSupplier(Class>> clazz) { - bind(new TypeLiteral>>() { - }).to(clazz).in(Scopes.SINGLETON); - } - -} \ No newline at end of file diff --git a/skeletons/standalone-compute/src/main/java/org/jclouds/servermanager/compute/config/ServerManagerComputeServiceContextModule.java b/skeletons/standalone-compute/src/main/java/org/jclouds/servermanager/compute/config/ServerManagerComputeServiceContextModule.java index c834e3f1b6..778a5446f7 100644 --- a/skeletons/standalone-compute/src/main/java/org/jclouds/servermanager/compute/config/ServerManagerComputeServiceContextModule.java +++ b/skeletons/standalone-compute/src/main/java/org/jclouds/servermanager/compute/config/ServerManagerComputeServiceContextModule.java @@ -22,7 +22,6 @@ import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.domain.Location; -import org.jclouds.location.suppliers.OnlyLocationOrFirstZone; import org.jclouds.servermanager.Datacenter; import org.jclouds.servermanager.Hardware; import org.jclouds.servermanager.Image; @@ -35,7 +34,6 @@ import org.jclouds.servermanager.compute.functions.ServerToNodeMetadata; import org.jclouds.servermanager.compute.strategy.ServerManagerComputeServiceAdapter; import com.google.common.base.Function; -import com.google.common.base.Supplier; import com.google.inject.TypeLiteral; /** @@ -62,7 +60,7 @@ public class ServerManagerComputeServiceContextModule extends }).to(ServerManagerHardwareToHardware.class); bind(new TypeLiteral>() { }).to(DatacenterToLocation.class); - bind(new TypeLiteral>() { - }).to(OnlyLocationOrFirstZone.class); + // to have the compute service adapter override default locations + install(new LocationsFromComputeServiceAdapterModule(){}); } } \ No newline at end of file