Repository: jclouds Updated Branches: refs/heads/master 27b3a844f -> c8bbb44f3
Enhance the way openstack extensions are resolved. Needed for new openstack versions. Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/c8bbb44f Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/c8bbb44f Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/c8bbb44f Branch: refs/heads/master Commit: c8bbb44f372677af2c7f60c7535a33d4c26b69c2 Parents: 27b3a84 Author: Zack Shoylev <[email protected]> Authored: Thu Feb 11 16:49:59 2016 -0600 Committer: Zack Shoylev <[email protected]> Committed: Tue Feb 16 15:18:39 2016 -0600 ---------------------------------------------------------------------- .../v2_0/config/KeystoneHttpApiModule.java | 4 +- ...nExtensionAnnotationMatchesExtensionSet.java | 123 +++++++++++++++++++ ...espaceEqualsAnyNamespaceInExtensionsSet.java | 102 --------------- ...ceEqualsAnyNamespaceInExtensionsSetTest.java | 39 +++--- .../nova/v2_0/config/NovaHttpApiModule.java | 4 +- 5 files changed, 145 insertions(+), 127 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/c8bbb44f/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneHttpApiModule.java ---------------------------------------------------------------------- diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneHttpApiModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneHttpApiModule.java index 149edd0..fc8aca3 100644 --- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneHttpApiModule.java +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneHttpApiModule.java @@ -36,7 +36,7 @@ import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAcces import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier; 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.openstack.v2_0.functions.PresentWhenExtensionAnnotationMatchesExtensionSet; import org.jclouds.openstack.v2_0.services.Identity; import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.annotations.ApiVersion; @@ -98,7 +98,7 @@ public class KeystoneHttpApiModule extends HttpApiModule<KeystoneApi> { @Override protected void configure() { - bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class); + bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationMatchesExtensionSet.class); super.configure(); namespaceAliasBinder(binder()); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/c8bbb44f/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationMatchesExtensionSet.java ---------------------------------------------------------------------- diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationMatchesExtensionSet.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationMatchesExtensionSet.java new file mode 100644 index 0000000..7507067 --- /dev/null +++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationMatchesExtensionSet.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.v2_0.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.any; +import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.aliasEquals; +import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.nameEquals; +import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.namespaceOrAliasEquals; +import static org.jclouds.util.Optionals2.unwrapIfOptional; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + +import org.jclouds.openstack.keystone.v2_0.config.NamespaceAliases; +import org.jclouds.openstack.v2_0.domain.Extension; +import org.jclouds.reflect.InvocationSuccess; +import org.jclouds.rest.functions.ImplicitOptionalConverter; + +import com.google.common.base.Optional; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; + +/** + * We use the annotation {@link Extension} to bind a class that implements an extension + * API to an {@link Extension}. + * + * Match in the following order: + * + * 1. Match by namespace + * 2. Match by namespace aliases + * 3. Match by alias + * 4. Match by name + * + * New versions of openstack have no namespaces anymore. + * Alias is different than a namespace alias - it's an alternative namespace URL to match against. + */ +public class PresentWhenExtensionAnnotationMatchesExtensionSet implements + ImplicitOptionalConverter { + private final LoadingCache<String, Set<? extends Extension>> extensions; + private final Map<URI, Set<URI>> aliases; + + @Inject + PresentWhenExtensionAnnotationMatchesExtensionSet( + LoadingCache<String, Set<? extends Extension>> extensions, @NamespaceAliases Map<URI, Set<URI>> aliases) { + this.extensions = extensions; + this.aliases = aliases == null ? ImmutableMap.<URI, Set<URI>> of() : ImmutableMap.copyOf(aliases); + } + + private boolean checkExtension(String invocationArg, URI namespace, + Set<URI> aliasesForNamespace, String alias, String name) { + if (any(extensions.getUnchecked(invocationArg), namespaceOrAliasEquals(namespace, aliasesForNamespace))) + return true; + // Could not find extension by namespace or namespace alias. Try to find it by alias next: + if ( !"".equals(alias)) { + if (any(extensions.getUnchecked(invocationArg), aliasEquals(alias))) + return true; + } + // Could not find extension by namespace or namespace alias or alias. Try to find it by name next: + if ( !"".equals(name)) { + if (any(extensions.getUnchecked(invocationArg), nameEquals(name))) + return true; + } + return false; + } + + @Override + public Optional<Object> apply(InvocationSuccess input) { + Class<?> target = unwrapIfOptional(input.getInvocation().getInvokable().getReturnType()); + Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(target + .getAnnotation(org.jclouds.openstack.v2_0.services.Extension.class)); + if (ext.isPresent()) { + URI namespace = URI.create(ext.get().namespace()); + List<Object> args = input.getInvocation().getArgs(); + Set<URI> aliasesForNamespace = aliases.containsKey(namespace) ? aliases.get(namespace) : Sets.<URI> newHashSet(); + String name = ext.get().name(); + String alias = ext.get().alias(); + + if (args.isEmpty()) { + if (checkExtension("", namespace, aliasesForNamespace, alias, name)) { + return input.getResult(); + } + } else if (args.size() == 1) { + String arg0 = checkNotNull(args.get(0), "arg[0] in %s", input).toString(); + if (checkExtension(arg0, namespace, aliasesForNamespace, alias, name)) { + return input.getResult(); + } + } else { + throw new RuntimeException(String.format("expecting zero or one args %s", input)); + } + + return Optional.absent(); + } else { + // No extension annotation, should check whether to return absent + return input.getResult(); + } + } + + @Override + public String toString() { + return "PresentWhenExtensionAnnotationMatchesExtensionSet()"; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/c8bbb44f/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.java ---------------------------------------------------------------------- diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.java deleted file mode 100644 index 101f06b..0000000 --- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jclouds.openstack.v2_0.functions; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Iterables.any; -import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.nameEquals; -import static org.jclouds.openstack.v2_0.predicates.ExtensionPredicates.namespaceOrAliasEquals; -import static org.jclouds.util.Optionals2.unwrapIfOptional; - -import java.net.URI; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; - -import org.jclouds.openstack.keystone.v2_0.config.NamespaceAliases; -import org.jclouds.openstack.v2_0.domain.Extension; -import org.jclouds.reflect.InvocationSuccess; -import org.jclouds.rest.functions.ImplicitOptionalConverter; - -import com.google.common.base.Optional; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Sets; - -/** - * We use the annotation {@link Extension} to bind a class that implements an extension - * API to an {@link Extension}. - */ -public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet implements - ImplicitOptionalConverter { - private final LoadingCache<String, Set<? extends Extension>> extensions; - private final Map<URI, Set<URI>> aliases; - - @Inject - PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet( - LoadingCache<String, Set<? extends Extension>> extensions, @NamespaceAliases Map<URI, Set<URI>> aliases) { - this.extensions = extensions; - this.aliases = aliases == null ? ImmutableMap.<URI, Set<URI>> of() : ImmutableMap.copyOf(aliases); - } - - @Override - public Optional<Object> apply(InvocationSuccess input) { - Class<?> target = unwrapIfOptional(input.getInvocation().getInvokable().getReturnType()); - Optional<org.jclouds.openstack.v2_0.services.Extension> ext = Optional.fromNullable(target - .getAnnotation(org.jclouds.openstack.v2_0.services.Extension.class)); - if (ext.isPresent()) { - URI namespace = URI.create(ext.get().namespace()); - List<Object> args = input.getInvocation().getArgs(); - Set<URI> aliasesForNamespace = aliases.containsKey(namespace) ? aliases.get(namespace) : Sets.<URI> newHashSet(); - String name = ext.get().name(); - - if (args.isEmpty()) { - if (any(extensions.getUnchecked(""), namespaceOrAliasEquals(namespace, aliasesForNamespace))) - return input.getResult(); - // Could not find extension by namespace or namespace alias. Try to find it by name next: - if ( !"".equals(name)) { - if (any(extensions.getUnchecked(""), nameEquals(name))) - return input.getResult(); - } - } else if (args.size() == 1) { - String arg0 = checkNotNull(args.get(0), "arg[0] in %s", input).toString(); - if (any(extensions.getUnchecked(arg0), namespaceOrAliasEquals(namespace, aliasesForNamespace))) - return input.getResult(); - // Could not find extension by namespace or namespace alias. Try to find it by name next: - if (!"".equals(name)) { - if (any(extensions.getUnchecked(arg0), nameEquals(name))) - return input.getResult(); - } - } else { - throw new RuntimeException(String.format("expecting zero or one args %s", input)); - } - - return Optional.absent(); - } else { - // No extension annotation, should check whether to return absent - return input.getResult(); - } - } - - @Override - public String toString() { - return "presentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet()"; - } - -} http://git-wip-us.apache.org/repos/asf/jclouds/blob/c8bbb44f/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java ---------------------------------------------------------------------- diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java index 4b6d479..7836140 100644 --- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java +++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java @@ -65,25 +65,17 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-06-16T00:00:00+00:00")).description( "Floating IPs support").build(); - @org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1") + @org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, name = "Floating_ips", alias = "os-floating-ips", namespace = "http://docs.openstack.org/ext/floating_ips/api/v1.1") interface FloatingIPApi { } - @org.jclouds.openstack.v2_0.services.Extension(of = ServiceType.COMPUTE, name = "Floating_ips", namespace = "http://docs.openstack.org/fake") - interface FloatingIPNamedApi { - - } - interface NovaApi { @Delegate Optional<FloatingIPApi> getFloatingIPExtensionApi(String region); @Delegate - Optional<FloatingIPNamedApi> getFloatingIPNamedExtensionApi(String region); - - @Delegate Optional<KeyPairApi> getKeyPairExtensionApi(String region); } @@ -93,11 +85,6 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio Invocation.create(method(NovaApi.class, "getFloatingIPExtensionApi", String.class), args), "foo"); } - InvocationSuccess getFloatingIPNamedExtension(List<Object> args) throws SecurityException, NoSuchMethodException { - return InvocationSuccess.create( - Invocation.create(method(NovaApi.class, "getFloatingIPNamedExtensionApi", String.class), args), "foo"); - } - InvocationSuccess getKeyPairExtension(List<Object> args) throws SecurityException, NoSuchMethodException { return InvocationSuccess.create( Invocation.create(method(NovaApi.class, "getKeyPairExtensionApi", String.class), args), "foo"); @@ -144,28 +131,38 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio * */ public void testPresentWhenNameSpaceIsMissingAndMatchByNameOrAlias() throws SecurityException, NoSuchMethodException { - Extension floatingIpsWithFakeNamespace = floatingIps.toBuilder() + // Revert to alias + Extension floatingIpsWithMissingNamespace = floatingIps.toBuilder() + .namespace(URI.create("http://docs.openstack.org/ext/fake")) + .build(); + + // Revert to name + Extension floatingIpsWithMissingNamespaceAndAlias = floatingIps.toBuilder() .namespace(URI.create("http://docs.openstack.org/ext/fake")) + .alias("fake") .build(); Multimap<URI, URI> aliases = ImmutableMultimap.of(); - assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithFakeNamespace), aliases).apply( - getFloatingIPNamedExtension(ImmutableList.<Object> of("region"))), Optional.of("foo")); + assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithMissingNamespace), aliases).apply( + getFloatingIPExtension(ImmutableList.<Object> of("region"))), Optional.of("foo")); + + assertEquals(whenExtensionsAndAliasesInRegionInclude("region", ImmutableSet.of(floatingIpsWithMissingNamespaceAndAlias), aliases).apply( + getFloatingIPExtension(ImmutableList.<Object> of("region"))), Optional.of("foo")); } - private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsInRegionInclude( + private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsInRegionInclude( String region, Extension... extensions) { return whenExtensionsAndAliasesInRegionInclude(region, ImmutableSet.copyOf(extensions), ImmutableMultimap.<URI, URI> of()); } - private PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet whenExtensionsAndAliasesInRegionInclude( + private PresentWhenExtensionAnnotationMatchesExtensionSet whenExtensionsAndAliasesInRegionInclude( String region, final Set<Extension> extensions, final Multimap<URI, URI> aliases) { final LoadingCache<String, Set<? extends Extension>> extensionsForRegion = CacheBuilder.newBuilder().build( CacheLoader.from(Functions.forMap(ImmutableMap.<String, Set<? extends Extension>>of(region, extensions, "differentregion", ImmutableSet.<Extension> of())))); - PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet fn = Guice.createInjector( + PresentWhenExtensionAnnotationMatchesExtensionSet fn = Guice.createInjector( new AbstractModule() { @Override protected void configure() { @@ -183,7 +180,7 @@ public class PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensio return extensionsForRegion; } - }).getInstance(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class); + }).getInstance(PresentWhenExtensionAnnotationMatchesExtensionSet.class); return fn; } http://git-wip-us.apache.org/repos/asf/jclouds/blob/c8bbb44f/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java ---------------------------------------------------------------------- diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java index dcbb519..c6d99ef 100644 --- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java +++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaHttpApiModule.java @@ -29,7 +29,7 @@ import org.jclouds.openstack.nova.v2_0.NovaApi; import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces; import org.jclouds.openstack.nova.v2_0.handlers.NovaErrorHandler; import org.jclouds.openstack.v2_0.domain.Extension; -import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet; +import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationMatchesExtensionSet; import org.jclouds.rest.ConfiguresHttpApi; import org.jclouds.rest.config.HttpApiModule; import org.jclouds.rest.functions.ImplicitOptionalConverter; @@ -54,7 +54,7 @@ public class NovaHttpApiModule extends HttpApiModule<NovaApi> { @Override protected void configure() { - bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class); + bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationMatchesExtensionSet.class); super.configure(); bindDefaultAliases(); }
