Make the OpenStack extension lists accessible for all APIs. Copied the Nova extension related code to the shared keystone package and added providers for extensions and aliases to all modules

This commit is contained in:
Andrew Donald Kennedy 2012-08-13 20:21:25 +01:00
parent f9a550529d
commit 0da2616737
32 changed files with 405 additions and 199 deletions

View File

@ -21,12 +21,16 @@ package org.jclouds.openstack.keystone.v2_0;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata; import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
import org.jclouds.openstack.keystone.v2_0.features.ServiceApi; import org.jclouds.openstack.keystone.v2_0.features.ServiceApi;
import org.jclouds.openstack.keystone.v2_0.features.TenantApi; import org.jclouds.openstack.keystone.v2_0.features.TenantApi;
import org.jclouds.openstack.keystone.v2_0.features.TokenApi; import org.jclouds.openstack.keystone.v2_0.features.TokenApi;
import org.jclouds.openstack.keystone.v2_0.features.UserApi; import org.jclouds.openstack.keystone.v2_0.features.UserApi;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam;
import com.google.common.base.Optional; import com.google.common.base.Optional;
@ -54,6 +58,12 @@ public interface KeystoneApi {
@Delegate @Delegate
ServiceApi getServiceApi(); ServiceApi getServiceApi();
/**
* Provides synchronous access to Extension features.
*/
@Delegate
ExtensionApi getExtensionApi();
/** /**
* Provides synchronous access to Token features * Provides synchronous access to Token features
*/ */
@ -66,7 +76,6 @@ public interface KeystoneApi {
@Delegate @Delegate
Optional<UserApi> getUserApi(); Optional<UserApi> getUserApi();
/** /**
* Provides synchronous access to Tenant features * Provides synchronous access to Tenant features
*/ */

View File

@ -27,6 +27,7 @@ import org.jclouds.openstack.keystone.v2_0.features.ServiceAsyncApi;
import org.jclouds.openstack.keystone.v2_0.features.TenantAsyncApi; import org.jclouds.openstack.keystone.v2_0.features.TenantAsyncApi;
import org.jclouds.openstack.keystone.v2_0.features.TokenAsyncApi; import org.jclouds.openstack.keystone.v2_0.features.TokenAsyncApi;
import org.jclouds.openstack.keystone.v2_0.features.UserAsyncApi; import org.jclouds.openstack.keystone.v2_0.features.UserAsyncApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
@ -60,6 +61,12 @@ public interface KeystoneAsyncApi {
@Delegate @Delegate
ServiceAsyncApi getServiceApi(); ServiceAsyncApi getServiceApi();
/**
* Provides asynchronous access to Extension features.
*/
@Delegate
ExtensionAsyncApi getExtensionApi();
/** /**
* @see KeystoneApi#getTokenApi() * @see KeystoneApi#getTokenApi()
*/ */
@ -72,7 +79,6 @@ public interface KeystoneAsyncApi {
@Delegate @Delegate
Optional<UserAsyncApi> getUserApi(); Optional<UserAsyncApi> getUserApi();
/** /**
* @see KeystoneApi#getTenantApi() * @see KeystoneApi#getTenantApi()
*/ */

View File

@ -23,6 +23,8 @@ import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -46,6 +48,9 @@ import org.jclouds.openstack.keystone.v2_0.handlers.KeystoneErrorHandler;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.services.Identity; import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.ApiVersion;
@ -54,7 +59,13 @@ import org.jclouds.rest.functions.ImplicitOptionalConverter;
import org.jclouds.util.Suppliers2; import org.jclouds.util.Suppliers2;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -70,17 +81,18 @@ public class KeystoneRestClientModule<S extends KeystoneApi, A extends KeystoneA
RestClientModule<S, A> { RestClientModule<S, A> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder() public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(ServiceApi.class, ServiceAsyncApi.class).put(TokenApi.class, TokenAsyncApi.class) .put(ServiceApi.class, ServiceAsyncApi.class)
.put(UserApi.class, UserAsyncApi.class).put(TenantApi.class, TenantAsyncApi.class).build(); .put(ExtensionApi.class, ExtensionAsyncApi.class)
.put(TokenApi.class, TokenAsyncApi.class)
.put(UserApi.class, UserAsyncApi.class)
.put(TenantApi.class, TenantAsyncApi.class)
.build();
@SuppressWarnings("unchecked")
public KeystoneRestClientModule() { public KeystoneRestClientModule() {
super(TypeToken.class.cast(TypeToken.of(KeystoneApi.class)), TypeToken.class.cast(TypeToken super(TypeToken.class.cast(TypeToken.of(KeystoneApi.class)), TypeToken.class.cast(TypeToken.of(KeystoneAsyncApi.class)), DELEGATE_MAP);
.of(KeystoneAsyncApi.class)), DELEGATE_MAP);
} }
protected KeystoneRestClientModule(TypeToken<S> syncApiType, TypeToken<A> asyncApiType, protected KeystoneRestClientModule(TypeToken<S> syncApiType, TypeToken<A> asyncApiType, Map<Class<?>, Class<?>> sync2Async) {
Map<Class<?>, Class<?>> sync2Async) {
super(syncApiType, asyncApiType, sync2Async); super(syncApiType, asyncApiType, sync2Async);
} }
@ -112,6 +124,25 @@ public class KeystoneRestClientModule<S extends KeystoneApi, A extends KeystoneA
} }
} }
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.build();
}
@Provides
@Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final javax.inject.Provider<KeystoneApi> keystoneApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(CacheLoader.from(Suppliers.memoize(new Supplier<Set<? extends Extension>>() {
@Override
public Set<? extends Extension> get() {
return keystoneApi.get().getExtensionApi().listExtensions();
}
})));
}
@Override @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(KeystoneErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(KeystoneErrorHandler.class);

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.domain; package org.jclouds.openstack.v2_0.domain;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -26,8 +26,6 @@ import java.util.Date;
import java.util.Set; import java.util.Set;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Resource;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;

View File

@ -16,13 +16,13 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.features; package org.jclouds.openstack.v2_0.features;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout; import org.jclouds.concurrent.Timeout;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
/** /**
* Provides asynchronous access to Extensions via their REST API. * Provides asynchronous access to Extensions via their REST API.

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.features; package org.jclouds.openstack.v2_0.features;
import java.util.Set; import java.util.Set;
@ -27,7 +27,7 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.functions; package org.jclouds.openstack.v2_0.functions;
import java.net.URI; import java.net.URI;
@ -25,7 +25,7 @@ import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import com.google.common.base.Function; import com.google.common.base.Function;

View File

@ -0,0 +1,86 @@
/**
* 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.openstack.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.net.URI;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.internal.ClassMethodArgsAndReturnVal;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.predicates.ExtensionPredicates;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
* We use the annotation {@link org.jclouds.openstack.services.Extension} to
* bind a class that iimplements an extension API to an {@link Extension}.
*
* @author Adrian Cole
*
*/
public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet implements
ImplicitOptionalConverter {
private final LoadingCache<String, Set<? extends Extension>> extensions;
private final Multimap<URI, URI> aliases;
@Inject
public PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
LoadingCache<String, Set<? extends Extension>> extensions,
Multimap<URI, URI> aliases) {
this.extensions = checkNotNull(extensions, "extensions");
this.aliases = aliases == null ? ImmutableMultimap.<URI, URI>of() : ImmutableMultimap.copyOf(aliases);
}
@Override
public Optional<Object> apply(ClassMethodArgsAndReturnVal input) {
Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(input.getClazz().getAnnotation(
org.jclouds.openstack.v2_0.services.Extension.class));
if (ext.isPresent()) {
URI namespace = URI.create(ext.get().namespace());
if (input.getArgs() == null || input.getArgs().length == 0) {
if (Iterables.any(extensions.getUnchecked(""),
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal());
} else if (input.getArgs() != null && input.getArgs().length == 1) {
if (Iterables.any(extensions.getUnchecked(checkNotNull(input.getArgs()[0], "arg[0] in %s", input).toString()),
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal());
} else {
throw new RuntimeException(String.format("expecting zero or one args %s", input));
}
}
return Optional.absent();
}
@Override
public String toString() {
return "presentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet()";
}
}

View File

@ -16,14 +16,14 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.predicates; package org.jclouds.openstack.v2_0.predicates;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Collection; import java.util.Collection;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;

View File

@ -1,4 +1,4 @@
package org.jclouds.openstack.nova.v2_0.functions; package org.jclouds.openstack.v2_0.functions;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -8,8 +8,7 @@ import javax.inject.Provider;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.sun.jersey.api.uri.UriBuilderImpl; import com.sun.jersey.api.uri.UriBuilderImpl;
@ -39,6 +38,6 @@ public class ExtensionToNameSpaceTest {
assertEquals(fn.apply(Extension.builder().alias("security_groups").name("SecurityGroups").namespace( assertEquals(fn.apply(Extension.builder().alias("security_groups").name("SecurityGroups").namespace(
URI.create("https://docs.openstack.org/ext/securitygroups/api/v1.1")).updated( URI.create("https://docs.openstack.org/ext/securitygroups/api/v1.1")).updated(
new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-07-21T00:00:00+00:00")).description( new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-07-21T00:00:00+00:00")).description(
"Security group support").build()), URI.create(ExtensionNamespaces.SECURITY_GROUPS)); "Security group support").build()), URI.create("http://docs.openstack.org/ext/securitygroups/api/v1.1"));
} }
} }

View File

@ -1,4 +1,4 @@
package org.jclouds.openstack.nova.v2_0.functions; package org.jclouds.openstack.v2_0.functions;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -9,10 +9,9 @@ import javax.inject.Named;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.internal.ClassMethodArgsAndReturnVal; import org.jclouds.internal.ClassMethodArgsAndReturnVal;
import org.jclouds.openstack.nova.v2_0.domain.Extension;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.openstack.nova.v2_0.extensions.KeyPairAsyncApi;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -40,8 +39,8 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-08-08T00:00:00+00:00")).description( new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-08-08T00:00:00+00:00")).description(
"Keypair Support").build(); "Keypair Support").build();
@org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.KEYPAIRS) @org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = "http://docs.openstack.org/ext/keypairs/api/v1.1")
static interface KeyPairIPAsyncApi { static interface KeyPairAsyncApi {
} }
@ -50,7 +49,7 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-06-16T00:00:00+00:00")).description( new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-06-16T00:00:00+00:00")).description(
"Floating IPs support").build(); "Floating IPs support").build();
@org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.FLOATING_IPS) @org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1")
static interface FloatingIPAsyncApi { static interface FloatingIPAsyncApi {
} }
@ -68,27 +67,27 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
ClassMethodArgsAndReturnVal getFloatingIPExtension() throws SecurityException, NoSuchMethodException { ClassMethodArgsAndReturnVal getFloatingIPExtension() throws SecurityException, NoSuchMethodException {
return ClassMethodArgsAndReturnVal.builder().clazz(FloatingIPAsyncApi.class).method( return ClassMethodArgsAndReturnVal.builder().clazz(FloatingIPAsyncApi.class).method(
NovaAsyncApi.class.getDeclaredMethod("getFloatingIPExtensionForZone", String.class)).args( NovaAsyncApi.class.getDeclaredMethod("getFloatingIPExtensionForZone", String.class)).args(
new Object[] { "expectedzone" }).returnVal("foo").build(); new Object[] { "zone" }).returnVal("foo").build();
} }
ClassMethodArgsAndReturnVal getKeyPairExtension() throws SecurityException, NoSuchMethodException { ClassMethodArgsAndReturnVal getKeyPairExtension() throws SecurityException, NoSuchMethodException {
return ClassMethodArgsAndReturnVal.builder().clazz(KeyPairAsyncApi.class).method( return ClassMethodArgsAndReturnVal.builder().clazz(KeyPairAsyncApi.class).method(
NovaAsyncApi.class.getDeclaredMethod("getKeyPairExtensionForZone", String.class)).args( NovaAsyncApi.class.getDeclaredMethod("getKeyPairExtensionForZone", String.class)).args(
new Object[] { "expectedzone" }).returnVal("foo").build(); new Object[] { "zone" }).returnVal("foo").build();
} }
public void testPresentWhenExtensionsIncludeNamespaceFromAnnotationAbsentWhenNot() throws SecurityException, NoSuchMethodException { public void testPresentWhenExtensionsIncludeNamespaceFromAnnotationAbsentWhenNot() throws SecurityException, NoSuchMethodException {
assertEquals(whenExtensionsInclude(keypairs, floatingIps).apply(getFloatingIPExtension()), Optional.of("foo")); assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getFloatingIPExtension()), Optional.of("foo"));
assertEquals(whenExtensionsInclude(keypairs, floatingIps).apply(getKeyPairExtension()), Optional.of("foo")); assertEquals(whenExtensionsInZoneInclude("zone", keypairs, floatingIps).apply(getKeyPairExtension()), Optional.of("foo"));
assertEquals(whenExtensionsInclude(keypairs).apply(getFloatingIPExtension()), Optional.absent()); assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply(getFloatingIPExtension()), Optional.absent());
assertEquals(whenExtensionsInclude(floatingIps).apply(getKeyPairExtension()), Optional.absent()); assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply(getKeyPairExtension()), Optional.absent());
} }
public void testZoneWithoutExtensionsReturnsAbsent() throws SecurityException, NoSuchMethodException { public void testZoneWithoutExtensionsReturnsAbsent() throws SecurityException, NoSuchMethodException {
assertEquals(whenExtensionsInclude(floatingIps).apply( assertEquals(whenExtensionsInZoneInclude("zone", floatingIps).apply(
getFloatingIPExtension().toBuilder().args(new Object[] { "differentzone" }).build()), Optional.absent()); getFloatingIPExtension().toBuilder().args(new Object[] { "differentzone" }).build()), Optional.absent());
assertEquals(whenExtensionsInclude(keypairs).apply( assertEquals(whenExtensionsInZoneInclude("zone", keypairs).apply(
getKeyPairExtension().toBuilder().args(new Object[] { "differentzone" }).build()), Optional.absent()); getKeyPairExtension().toBuilder().args(new Object[] { "differentzone" }).build()), Optional.absent());
} }
@ -105,22 +104,22 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
Multimap<URI, URI> aliases = ImmutableMultimap.of(keypairs.getNamespace(), keypairsWithDifferentNamespace Multimap<URI, URI> aliases = ImmutableMultimap.of(keypairs.getNamespace(), keypairsWithDifferentNamespace
.getNamespace()); .getNamespace());
assertEquals(whenExtensionsAndAliasesInclude(ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply( assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply(
getKeyPairExtension()), Optional.of("foo")); getKeyPairExtension()), Optional.of("foo"));
assertEquals(whenExtensionsAndAliasesInclude(ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply( assertEquals(whenExtensionsAndAliasesInZoneInclude("zone", ImmutableSet.of(keypairsWithDifferentNamespace), aliases).apply(
getFloatingIPExtension()), Optional.absent()); getFloatingIPExtension()), Optional.absent());
} }
private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsInclude( private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsInZoneInclude(
Extension... extensions) { String zone, Extension... extensions) {
return whenExtensionsAndAliasesInclude(ImmutableSet.copyOf(extensions), ImmutableMultimap.<URI, URI> of()); return whenExtensionsAndAliasesInZoneInclude(zone, ImmutableSet.copyOf(extensions), ImmutableMultimap.<URI, URI> of());
} }
private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsAndAliasesInclude( private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsAndAliasesInZoneInclude(
final Set<Extension> extensions, final Multimap<URI, URI> aliases) { String zone, final Set<Extension> extensions, final Multimap<URI, URI> aliases) {
final LoadingCache<String, Set<? extends Extension>> extensionsForZone = CacheBuilder.newBuilder().build( final LoadingCache<String, Set<? extends Extension>> extensionsForZone = CacheBuilder.newBuilder().build(
CacheLoader.from(Functions.forMap(ImmutableMap.<String, Set<? extends Extension>>of("expectedzone", extensions, "differentzone", CacheLoader.from(Functions.forMap(ImmutableMap.<String, Set<? extends Extension>>of(zone, extensions, "differentzone",
ImmutableSet.<Extension> of())))); ImmutableSet.<Extension> of()))));
PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet fn = Guice.createInjector( PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet fn = Guice.createInjector(
@ -135,7 +134,6 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio
} }
@Provides @Provides
@Named("openstack.nova.extensions")
Multimap<URI, URI> getAliases() { Multimap<URI, URI> getAliases() {
return aliases; return aliases;
} }

View File

@ -16,15 +16,15 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v2_0.predicates; package org.jclouds.openstack.v2_0.predicates;
import static org.jclouds.openstack.nova.v2_0.predicates.ExtensionPredicates.aliasEquals; import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.aliasEquals;
import static org.jclouds.openstack.nova.v2_0.predicates.ExtensionPredicates.namespaceEquals; import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.namespaceEquals;
import java.net.URI; import java.net.URI;
import org.jclouds.date.internal.SimpleDateFormatDateService; import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**

View File

@ -39,10 +39,10 @@ import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi; import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
import org.jclouds.openstack.nova.v2_0.features.ExtensionApi;
import org.jclouds.openstack.nova.v2_0.features.FlavorApi; import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
import org.jclouds.openstack.nova.v2_0.features.ImageApi; import org.jclouds.openstack.nova.v2_0.features.ImageApi;
import org.jclouds.openstack.nova.v2_0.features.ServerApi; import org.jclouds.openstack.nova.v2_0.features.ServerApi;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;

View File

@ -37,10 +37,10 @@ import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi; import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi; import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ServerAsyncApi; import org.jclouds.openstack.nova.v2_0.features.ServerAsyncApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.openstack.nova.v2_0.config; package org.jclouds.openstack.nova.v2_0.config;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -29,47 +30,48 @@ import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection; import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError; import org.jclouds.http.annotation.ServerError;
import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
import org.jclouds.openstack.nova.v2_0.NovaApi; import org.jclouds.openstack.nova.v2_0.NovaApi;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsApi; import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsApi;
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi; import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi; import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi;
import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateApi;
import org.jclouds.openstack.nova.v2_0.extensions.KeyPairAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.HostAggregateAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi; import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.KeyPairAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaApi; import org.jclouds.openstack.nova.v2_0.extensions.QuotaApi;
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.QuotaAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi;
import org.jclouds.openstack.nova.v2_0.extensions.QuotaClassAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi; import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi; import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsApi;
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.ServerWithSecurityGroupsAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi; import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageApi;
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.SimpleTenantUsageAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi; import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VirtualInterfaceAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi;
import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeApi;
import org.jclouds.openstack.nova.v2_0.features.ExtensionAsyncApi; import org.jclouds.openstack.nova.v2_0.extensions.VolumeTypeAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ExtensionApi;
import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.FlavorApi; import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi; import org.jclouds.openstack.nova.v2_0.features.FlavorAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ImageApi; import org.jclouds.openstack.nova.v2_0.features.ImageApi;
import org.jclouds.openstack.nova.v2_0.features.ServerAsyncApi; import org.jclouds.openstack.nova.v2_0.features.ImageAsyncApi;
import org.jclouds.openstack.nova.v2_0.features.ServerApi; import org.jclouds.openstack.nova.v2_0.features.ServerApi;
import org.jclouds.openstack.nova.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet; import org.jclouds.openstack.nova.v2_0.features.ServerAsyncApi;
import org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler; import org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.functions.ImplicitOptionalConverter; import org.jclouds.rest.functions.ImplicitOptionalConverter;
@ -78,6 +80,8 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -127,17 +131,50 @@ public class NovaRestClientModule<S extends NovaApi, A extends NovaAsyncApi> ext
super.configure(); super.configure();
} }
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.put(URI.create(ExtensionNamespaces.SECURITY_GROUPS),
URI.create("http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLOATING_IPS),
URI.create("http://docs.openstack.org/compute/ext/floating_ips/api/v1.1"))
.put(URI.create(ExtensionNamespaces.KEYPAIRS),
URI.create("http://docs.openstack.org/compute/ext/keypairs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.SIMPLE_TENANT_USAGE),
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
.put(URI.create(ExtensionNamespaces.HOSTS),
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUMES),
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AGGREGATES),
URI.create("http://docs.openstack.org/compute/ext/aggregates/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLAVOR_EXTRA_SPECS),
URI.create("http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTAS),
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTA_CLASSES),
URI.create("http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_TYPES),
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"))
.build();
}
@Provides @Provides
@Singleton @Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<NovaApi> novaApi) { public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<NovaApi> novaApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS) return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() { .build(new CacheLoader<String, Set<? extends Extension>>() {
@Override @Override
public Set<? extends Extension> load(String key) throws Exception { public Set<? extends Extension> load(String key) throws Exception {
return novaApi.get().getExtensionApiForZone(key).listExtensions(); return novaApi.get().getExtensionApiForZone(key).listExtensions();
} }
}); });
} }

View File

@ -31,8 +31,8 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v2_0.domain.FloatingIP; import org.jclouds.openstack.nova.v2_0.domain.FloatingIP;
import org.jclouds.openstack.nova.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.services.Extension; import org.jclouds.openstack.v2_0.services.Extension;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.Payload;

View File

@ -32,8 +32,8 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.nova.v2_0.domain.KeyPair; import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
import org.jclouds.openstack.nova.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.openstack.v2_0.services.Extension; import org.jclouds.openstack.v2_0.services.Extension;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.annotations.Payload;

View File

@ -1,113 +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.openstack.nova.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.net.URI;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.internal.ClassMethodArgsAndReturnVal;
import org.jclouds.openstack.nova.v2_0.domain.Extension;
import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
import org.jclouds.openstack.nova.v2_0.predicates.ExtensionPredicates;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
import com.google.common.base.Optional;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
* We use the annotation {@link org.jclouds.openstack.services.Extension} to
* bind a class that is an extension to an extension found in the
* {@link org.jclouds.openstack.nova.v2_0.features.ExtensionApi#listExtensions} call.
*
* @author Adrian Cole
*
*/
@Singleton
public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet implements
ImplicitOptionalConverter {
private final LoadingCache<String, Set<? extends Extension>> extensions;
@com.google.inject.Inject(optional=true)
@Named("openstack.nova.extensions")
Multimap<URI, URI> aliases = ImmutableMultimap.<URI, URI>builder()
.put(URI.create(ExtensionNamespaces.SECURITY_GROUPS),
URI.create("http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLOATING_IPS),
URI.create("http://docs.openstack.org/compute/ext/floating_ips/api/v1.1"))
.put(URI.create(ExtensionNamespaces.KEYPAIRS),
URI.create("http://docs.openstack.org/compute/ext/keypairs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.SIMPLE_TENANT_USAGE),
URI.create("http://docs.openstack.org/compute/ext/os-simple-tenant-usage/api/v1.1"))
.put(URI.create(ExtensionNamespaces.HOSTS),
URI.create("http://docs.openstack.org/compute/ext/hosts/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUMES),
URI.create("http://docs.openstack.org/compute/ext/volumes/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VIRTUAL_INTERFACES),
URI.create("http://docs.openstack.org/compute/ext/virtual_interfaces/api/v1.1"))
.put(URI.create(ExtensionNamespaces.CREATESERVEREXT),
URI.create("http://docs.openstack.org/compute/ext/createserverext/api/v1.1"))
.put(URI.create(ExtensionNamespaces.ADMIN_ACTIONS),
URI.create("http://docs.openstack.org/compute/ext/admin-actions/api/v1.1"))
.put(URI.create(ExtensionNamespaces.AGGREGATES),
URI.create("http://docs.openstack.org/compute/ext/aggregates/api/v1.1"))
.put(URI.create(ExtensionNamespaces.FLAVOR_EXTRA_SPECS),
URI.create("http://docs.openstack.org/compute/ext/flavor_extra_specs/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTAS),
URI.create("http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.QUOTA_CLASSES),
URI.create("http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1"))
.put(URI.create(ExtensionNamespaces.VOLUME_TYPES),
URI.create("http://docs.openstack.org/compute/ext/volume_types/api/v1.1"))
.build();
@Inject
public PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet(
LoadingCache<String, Set<? extends Extension>> extensions) {
this.extensions = checkNotNull(extensions, "extensions");
}
@Override
public Optional<Object> apply(ClassMethodArgsAndReturnVal input) {
Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(input.getClazz().getAnnotation(
org.jclouds.openstack.v2_0.services.Extension.class));
if (ext.isPresent()) {
checkState(input.getArgs() != null && input.getArgs().length == 1, "expecting an arg %s", input);
URI namespace = URI.create(ext.get().namespace());
if (Iterables.any(extensions.getUnchecked(checkNotNull(input.getArgs()[0], "arg[0] in %s", input).toString()),
ExtensionPredicates.namespaceOrAliasEquals(namespace, aliases.get(namespace))))
return Optional.of(input.getReturnVal());
}
return Optional.absent();
}
public String toString() {
return "presentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet()";
}
}

View File

@ -27,11 +27,11 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.openstack.nova.v2_0.domain.BackupType; import org.jclouds.openstack.nova.v2_0.domain.BackupType;
import org.jclouds.openstack.nova.v2_0.domain.Image; import org.jclouds.openstack.nova.v2_0.domain.Image;
import org.jclouds.openstack.nova.v2_0.domain.Server.Status; import org.jclouds.openstack.nova.v2_0.domain.Server.Status;
import org.jclouds.openstack.nova.v2_0.features.ExtensionApi;
import org.jclouds.openstack.nova.v2_0.features.ImageApi; import org.jclouds.openstack.nova.v2_0.features.ImageApi;
import org.jclouds.openstack.nova.v2_0.features.ServerApi; import org.jclouds.openstack.nova.v2_0.features.ServerApi;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions; import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterGroups;
import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeGroups;

View File

@ -23,8 +23,9 @@ import static org.testng.Assert.assertTrue;
import java.util.Set; import java.util.Set;
import org.jclouds.openstack.nova.v2_0.domain.Extension;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest; import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**

View File

@ -28,7 +28,7 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseSetParserTest; import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule; import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;

View File

@ -28,7 +28,7 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseSetParserTest; import org.jclouds.json.BaseSetParserTest;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule; import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.domain.Link; import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Link.Relation; import org.jclouds.openstack.v2_0.domain.Link.Relation;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;

View File

@ -27,7 +27,7 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest; import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.nova.v2_0.config.NovaParserModule; import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
import org.jclouds.openstack.nova.v2_0.domain.Extension; import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.domain.Link; import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Link.Relation; import org.jclouds.openstack.v2_0.domain.Link.Relation;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;

View File

@ -26,6 +26,7 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.glance.v1_0.features.ImageApi; import org.jclouds.openstack.glance.v1_0.features.ImageApi;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -49,6 +50,13 @@ public interface GlanceApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides synchronous access to Extension features.
*/
@Delegate
ExtensionApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides synchronous access to Image features. * Provides synchronous access to Image features.
*/ */

View File

@ -24,6 +24,7 @@ import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.glance.v1_0.features.ImageAsyncApi; import org.jclouds.openstack.glance.v1_0.features.ImageAsyncApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -46,6 +47,13 @@ public interface GlanceAsyncApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides asynchronous access to Extension features.
*/
@Delegate
ExtensionAsyncApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides asynchronous access to Image features. * Provides asynchronous access to Image features.
*/ */

View File

@ -18,7 +18,13 @@
*/ */
package org.jclouds.openstack.glance.v1_0.config; package org.jclouds.openstack.glance.v1_0.config;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
@ -31,11 +37,20 @@ import org.jclouds.openstack.glance.v1_0.GlanceAsyncApi;
import org.jclouds.openstack.glance.v1_0.features.ImageApi; import org.jclouds.openstack.glance.v1_0.features.ImageApi;
import org.jclouds.openstack.glance.v1_0.features.ImageAsyncApi; import org.jclouds.openstack.glance.v1_0.features.ImageAsyncApi;
import org.jclouds.openstack.glance.v1_0.handlers.GlanceErrorHandler; import org.jclouds.openstack.glance.v1_0.handlers.GlanceErrorHandler;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Provides;
/** /**
* Configures the Glance connection. * Configures the Glance connection.
@ -46,6 +61,7 @@ import com.google.common.reflect.TypeToken;
public class GlanceRestClientModule<S extends GlanceApi, A extends GlanceAsyncApi> extends RestClientModule<S, A> { public class GlanceRestClientModule<S extends GlanceApi, A extends GlanceAsyncApi> extends RestClientModule<S, A> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder() public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(ExtensionApi.class, ExtensionAsyncApi.class)
.put(ImageApi.class, ImageAsyncApi.class) .put(ImageApi.class, ImageAsyncApi.class)
.build(); .build();
@ -63,6 +79,25 @@ public class GlanceRestClientModule<S extends GlanceApi, A extends GlanceAsyncAp
super.configure(); super.configure();
} }
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.build();
}
@Provides
@Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<GlanceApi> glanceApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() {
@Override
public Set<? extends Extension> load(String key) throws Exception {
return glanceApi.get().getExtensionApiForRegion(key).listExtensions();
}
});
}
@Override @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GlanceErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GlanceErrorHandler.class);

View File

@ -28,8 +28,10 @@ import org.jclouds.concurrent.Timeout;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.location.functions.ZoneToEndpoint;
import org.jclouds.openstack.quantum.v1_0.features.NetworkApi; import org.jclouds.openstack.quantum.v1_0.features.NetworkApi;
import org.jclouds.openstack.quantum.v1_0.features.PortApi; import org.jclouds.openstack.quantum.v1_0.features.PortApi;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -52,6 +54,13 @@ public interface QuantumApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides synchronous access to Extension features.
*/
@Delegate
ExtensionApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides synchronous access to Network features. * Provides synchronous access to Network features.
*/ */

View File

@ -28,6 +28,7 @@ import org.jclouds.location.Region;
import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.quantum.v1_0.features.NetworkAsyncApi; import org.jclouds.openstack.quantum.v1_0.features.NetworkAsyncApi;
import org.jclouds.openstack.quantum.v1_0.features.PortAsyncApi; import org.jclouds.openstack.quantum.v1_0.features.PortAsyncApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -50,6 +51,13 @@ public interface QuantumAsyncApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides asynchronous access to Extension features.
*/
@Delegate
ExtensionAsyncApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides asynchronous access to Network features. * Provides asynchronous access to Network features.
*/ */

View File

@ -18,7 +18,13 @@
*/ */
package org.jclouds.openstack.quantum.v1_0.config; package org.jclouds.openstack.quantum.v1_0.config;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
@ -33,11 +39,20 @@ import org.jclouds.openstack.quantum.v1_0.features.NetworkAsyncApi;
import org.jclouds.openstack.quantum.v1_0.features.PortApi; import org.jclouds.openstack.quantum.v1_0.features.PortApi;
import org.jclouds.openstack.quantum.v1_0.features.PortAsyncApi; import org.jclouds.openstack.quantum.v1_0.features.PortAsyncApi;
import org.jclouds.openstack.quantum.v1_0.handlers.QuantumErrorHandler; import org.jclouds.openstack.quantum.v1_0.handlers.QuantumErrorHandler;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Provides;
/** /**
* Configures the Quantum connection. * Configures the Quantum connection.
@ -48,6 +63,7 @@ import com.google.common.reflect.TypeToken;
public class QuantumRestClientModule<S extends QuantumApi, A extends QuantumAsyncApi> extends RestClientModule<S, A> { public class QuantumRestClientModule<S extends QuantumApi, A extends QuantumAsyncApi> extends RestClientModule<S, A> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder() public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(ExtensionApi.class, ExtensionAsyncApi.class)
.put(NetworkApi.class, NetworkAsyncApi.class) .put(NetworkApi.class, NetworkAsyncApi.class)
.put(PortApi.class, PortAsyncApi.class) .put(PortApi.class, PortAsyncApi.class)
.build(); .build();
@ -66,6 +82,25 @@ public class QuantumRestClientModule<S extends QuantumApi, A extends QuantumAsyn
super.configure(); super.configure();
} }
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.build();
}
@Provides
@Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<QuantumApi> quantumApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() {
@Override
public Set<? extends Extension> load(String key) throws Exception {
return quantumApi.get().getExtensionApiForRegion(key).listExtensions();
}
});
}
@Override @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(QuantumErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(QuantumErrorHandler.class);

View File

@ -28,6 +28,7 @@ import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.swift.v1.features.AccountApi; import org.jclouds.openstack.swift.v1.features.AccountApi;
import org.jclouds.openstack.swift.v1.features.ContainerApi; import org.jclouds.openstack.swift.v1.features.ContainerApi;
import org.jclouds.openstack.swift.v1.features.ObjectApi; import org.jclouds.openstack.swift.v1.features.ObjectApi;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -51,6 +52,13 @@ public interface SwiftApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides synchronous access to Extension features.
*/
@Delegate
ExtensionApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides synchronous access to Account features. * Provides synchronous access to Account features.
*/ */

View File

@ -26,6 +26,7 @@ import org.jclouds.location.functions.RegionToEndpoint;
import org.jclouds.openstack.swift.v1.features.AccountAsyncApi; import org.jclouds.openstack.swift.v1.features.AccountAsyncApi;
import org.jclouds.openstack.swift.v1.features.ContainerAsyncApi; import org.jclouds.openstack.swift.v1.features.ContainerAsyncApi;
import org.jclouds.openstack.swift.v1.features.ObjectAsyncApi; import org.jclouds.openstack.swift.v1.features.ObjectAsyncApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.Delegate;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
@ -48,6 +49,13 @@ public interface SwiftAsyncApi {
@Region @Region
Set<String> getConfiguredRegions(); Set<String> getConfiguredRegions();
/**
* Provides asynchronous access to Extension features.
*/
@Delegate
ExtensionAsyncApi getExtensionApiForRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
/** /**
* Provides asynchronous access to Account features. * Provides asynchronous access to Account features.
*/ */

View File

@ -18,7 +18,13 @@
*/ */
package org.jclouds.openstack.swift.v1.config; package org.jclouds.openstack.swift.v1.config;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.http.HttpErrorHandler; import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError; import org.jclouds.http.annotation.ClientError;
@ -35,11 +41,20 @@ import org.jclouds.openstack.swift.v1.features.ContainerAsyncApi;
import org.jclouds.openstack.swift.v1.features.ObjectApi; import org.jclouds.openstack.swift.v1.features.ObjectApi;
import org.jclouds.openstack.swift.v1.features.ObjectAsyncApi; import org.jclouds.openstack.swift.v1.features.ObjectAsyncApi;
import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler; import org.jclouds.openstack.swift.v1.handlers.SwiftErrorHandler;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.features.ExtensionApi;
import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.RestClientModule;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Provides;
/** /**
* Configures the Swift connection. * Configures the Swift connection.
@ -50,6 +65,7 @@ import com.google.common.reflect.TypeToken;
public class SwiftRestClientModule<S extends SwiftApi, A extends SwiftAsyncApi> extends RestClientModule<S, A> { public class SwiftRestClientModule<S extends SwiftApi, A extends SwiftAsyncApi> extends RestClientModule<S, A> {
public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder() public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
.put(ExtensionApi.class, ExtensionAsyncApi.class)
.put(AccountApi.class, AccountAsyncApi.class) .put(AccountApi.class, AccountAsyncApi.class)
.put(ContainerApi.class, ContainerAsyncApi.class) .put(ContainerApi.class, ContainerAsyncApi.class)
.put(ObjectApi.class, ObjectAsyncApi.class) .put(ObjectApi.class, ObjectAsyncApi.class)
@ -69,6 +85,25 @@ public class SwiftRestClientModule<S extends SwiftApi, A extends SwiftAsyncApi>
super.configure(); super.configure();
} }
@Provides
@Singleton
public Multimap<URI, URI> aliases() {
return ImmutableMultimap.<URI, URI>builder()
.build();
}
@Provides
@Singleton
public LoadingCache<String, Set<? extends Extension>> provideExtensionsByZone(final Provider<SwiftApi> swiftApi) {
return CacheBuilder.newBuilder().expireAfterWrite(23, TimeUnit.HOURS)
.build(new CacheLoader<String, Set<? extends Extension>>() {
@Override
public Set<? extends Extension> load(String key) throws Exception {
return swiftApi.get().getExtensionApiForRegion(key).listExtensions();
}
});
}
@Override @Override
protected void bindErrorHandlers() { protected void bindErrorHandlers() {
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SwiftErrorHandler.class); bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SwiftErrorHandler.class);