decoupled code that requires async apis from keystone

This commit is contained in:
adriancole 2013-04-09 18:31:14 -07:00
parent dce0ecd889
commit e613c95eb9
7 changed files with 196 additions and 53 deletions

View File

@ -18,47 +18,88 @@
*/ */
package org.jclouds.openstack.keystone.v2_0; package org.jclouds.openstack.keystone.v2_0;
import java.io.Closeable;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.v2_0.binders.BindAuthToJsonPayload;
import org.jclouds.openstack.keystone.v2_0.domain.Access; import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials; import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials; import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.SelectJson;
import com.google.inject.name.Named;
/** /**
* Provides synchronous access to the KeyStone Service API. * Provides synchronous access to the KeyStone Service API.
* <p/> * <p/>
* *
* @see AuthenticationAsyncApi * @see <a href=
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Api_Operations.html" * "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Api_Operations.html"
* /> * />
* @author Adrian Cole * @author Adrian Cole
*/ */
public interface AuthenticationApi { public interface AuthenticationApi extends Closeable {
/** /**
* Authenticate to generate a token. * Authenticate to generate a token.
* *
* @return access with token * @return access with token
*/ */
Access authenticateWithTenantNameAndCredentials(@Nullable String tenantId, PasswordCredentials passwordCredentials); @Named("authenticate")
@POST
@SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantNameAndCredentials(@Nullable @PayloadParam("tenantName") String tenantName,
PasswordCredentials passwordCredentials);
/** /**
* Authenticate to generate a token. * Authenticate to generate a token.
* *
* @return access with token * @return access with token
*/ */
Access authenticateWithTenantIdAndCredentials(@Nullable String tenantId, PasswordCredentials passwordCredentials); @Named("authenticate")
@POST
@SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantIdAndCredentials(@Nullable @PayloadParam("tenantId") String tenantId,
PasswordCredentials passwordCredentials);
/** /**
* Authenticate to generate a token. * Authenticate to generate a token.
* *
* @return access with token * @return access with token
*/ */
Access authenticateWithTenantNameAndCredentials(@Nullable String tenantId, ApiAccessKeyCredentials passwordCredentials); @Named("authenticate")
@POST
@SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantNameAndCredentials(@Nullable @PayloadParam("tenantName") String tenantName,
ApiAccessKeyCredentials apiAccessKeyCredentials);
/** /**
* Authenticate to generate a token. * Authenticate to generate a token.
* *
* @return access with token * @return access with token
*/ */
Access authenticateWithTenantIdAndCredentials(@Nullable String tenantId, ApiAccessKeyCredentials passwordCredentials); @Named("authenticate")
@POST
@SelectJson("access")
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantIdAndCredentials(@Nullable @PayloadParam("tenantId") String tenantId,
ApiAccessKeyCredentials apiAccessKeyCredentials);
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.openstack.keystone.v2_0; package org.jclouds.openstack.keystone.v2_0;
import java.io.Closeable;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -42,8 +44,11 @@ import com.google.common.util.concurrent.ListenableFuture;
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Api_Operations.html" * @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Service_API_Api_Operations.html"
* /> * />
* @author Adrian Cole * @author Adrian Cole
* @deprecated will be removed in jclouds 1.7, as async interfaces are no longer
* supported. please use {@link AuthenticationApi}
*/ */
public interface AuthenticationAsyncApi { @Deprecated
public interface AuthenticationAsyncApi extends Closeable {
/** /**
* @see AuthenticationApi#authenticateWithTenantNameAndCredentials(String,PasswordCredentials) * @see AuthenticationApi#authenticateWithTenantNameAndCredentials(String,PasswordCredentials)

View File

@ -29,6 +29,7 @@ import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneParserModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneParserModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneRestClientModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneRestClientModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneRestClientModule.KeystoneAdminURLModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneRestClientModule.KeystoneAdminURLModule;
import org.jclouds.openstack.keystone.v2_0.config.MappedAuthenticationApiModule;
import org.jclouds.openstack.v2_0.ServiceType; import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.rest.internal.BaseRestApiMetadata; import org.jclouds.rest.internal.BaseRestApiMetadata;
@ -90,6 +91,7 @@ public class KeystoneApiMetadata extends BaseRestApiMetadata {
.defaultEndpoint("http://localhost:5000/v${jclouds.api-version}/") .defaultEndpoint("http://localhost:5000/v${jclouds.api-version}/")
.defaultProperties(KeystoneApiMetadata.defaultProperties()) .defaultProperties(KeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder() .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(MappedAuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class) .add(KeystoneAuthenticationModule.class)
.add(KeystoneAdminURLModule.class) .add(KeystoneAdminURLModule.class)
.add(KeystoneParserModule.class) .add(KeystoneParserModule.class)

View File

@ -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.openstack.keystone.v2_0.config;
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import com.google.inject.AbstractModule;
/**
*
* @author Adrian Cole
*/
public class AuthenticationApiModule extends AbstractModule {
@Override
protected void configure() {
// AuthenticationApi is used directly for filters and retry handlers, so let's bind it explicitly
bindHttpApi(binder(), AuthenticationApi.class);
}
}

View File

@ -19,7 +19,6 @@
package org.jclouds.openstack.keystone.v2_0.config; package org.jclouds.openstack.keystone.v2_0.config;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.rest.config.BinderUtils.bindMappedHttpApi;
import static org.jclouds.util.Suppliers2.getLastValueInMap; import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI; import java.net.URI;
@ -47,8 +46,6 @@ import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
import org.jclouds.location.suppliers.derived.ZoneIdsFromZoneIdToURIKeySet; import org.jclouds.location.suppliers.derived.ZoneIdsFromZoneIdToURIKeySet;
import org.jclouds.location.suppliers.implicit.FirstRegion; import org.jclouds.location.suppliers.implicit.FirstRegion;
import org.jclouds.location.suppliers.implicit.FirstZone; import org.jclouds.location.suppliers.implicit.FirstZone;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncApi;
import org.jclouds.openstack.keystone.v2_0.domain.Access; import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint; import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials; import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials;
@ -60,7 +57,6 @@ import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.ZoneIdToURIFromAccessForTypeAndVersion; import org.jclouds.openstack.keystone.v2_0.suppliers.ZoneIdToURIFromAccessForTypeAndVersion;
import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -89,7 +85,7 @@ public class KeystoneAuthenticationModule extends AbstractModule {
* {@link javax.inject.Qualifier}</li> * {@link javax.inject.Qualifier}</li>
* <li>add the above annotation to any {@link AsyncApi} classes by placing it on the type. ex. * <li>add the above annotation to any {@link AsyncApi} classes by placing it on the type. ex.
* {@code @Endpoint(CloudDNS.class)}</li> * {@code @Endpoint(CloudDNS.class)}</li>
* <li>add the following to your {@link RestClientModule}</li> * <li>add the following to your {@link org.jclouds.rest.config.RestClientModule}</li>
* *
* <pre> * <pre>
* bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() { * bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
@ -184,12 +180,6 @@ public class KeystoneAuthenticationModule extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class); bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
bindAuthenticationApi();
}
protected void bindAuthenticationApi() {
// AuthenticationApi is used directly for filters and retry handlers, so let's bind it explicitly
bindMappedHttpApi(binder(), AuthenticationApi.class, AuthenticationAsyncApi.class);
} }
/** /**

View File

@ -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.openstack.keystone.v2_0.config;
import static org.jclouds.rest.config.BinderUtils.bindMappedHttpApi;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import org.jclouds.openstack.keystone.v2_0.AuthenticationAsyncApi;
import com.google.inject.AbstractModule;
/**
*
* @author Adrian Cole
* @deprecated will be removed in jclouds 1.7, as async interfaces are no longer
* supported. please use {@link AuthenticationApiModule}
*/
@Deprecated
public class MappedAuthenticationApiModule extends AbstractModule {
@Override
protected void configure() {
// AuthenticationApi is used directly for filters and retry handlers, so let's bind it explicitly
bindMappedHttpApi(binder(), AuthenticationApi.class, AuthenticationAsyncApi.class);
}
}

View File

@ -1,9 +1,28 @@
/**
* 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.keystone.v2_0.config; package org.jclouds.openstack.keystone.v2_0.config;
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE; import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE; import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import java.io.Closeable; import java.io.Closeable;
@ -13,6 +32,7 @@ import java.net.URI;
import java.util.Properties; import java.util.Properties;
import javax.inject.Qualifier; import javax.inject.Qualifier;
import javax.inject.Singleton;
import javax.ws.rs.HEAD; import javax.ws.rs.HEAD;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
@ -23,21 +43,23 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.KeystoneApi; import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ProviderModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ProviderModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest; import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.config.HttpApiModule;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
import org.jclouds.rest.internal.BaseRestApiExpectTest; import org.jclouds.rest.internal.BaseRestApiExpectTest;
import org.jclouds.rest.internal.BaseRestApiMetadata;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral; import com.google.inject.Provides;
/** /**
* Tests configuration via {@link ProviderModule} * Tests configuration via {@link ProviderModule}
@ -48,31 +70,34 @@ import com.google.inject.TypeLiteral;
public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModuleExpectTest.DNSApi> { public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModuleExpectTest.DNSApi> {
@Retention(RUNTIME) @Retention(RUNTIME)
@Target(TYPE) @Target(METHOD)
@Qualifier @Qualifier
static @interface DNS { static @interface DNS {
} }
@ConfiguresRestClient @ConfiguresHttpApi
public static class DNSRestClientModule extends RestClientModule<DNSApi, DNSAsyncApi> { public static class DNSHttpApiModule extends HttpApiModule<DNSApi> {
@Override @Override
public void configure() { public void configure() {
bind(new TypeLiteral<Supplier<URI>>() {}).annotatedWith(DNS.class).to(new TypeLiteral<Supplier<URI>>() {});
bind(DateAdapter.class).to(Iso8601DateAdapter.class); bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure(); super.configure();
} }
}
static interface DNSApi extends Closeable { @Provides
boolean zoneExists(@PathParam("zoneName") String zoneName); @Singleton
@DNS
protected Supplier<URI> provideCDNUrl(RegionIdToURISupplier.Factory factory, @ApiVersion String apiVersion) {
return getLastValueInMap(factory.createForApiTypeAndVersion("dns", apiVersion));
}
} }
@org.jclouds.rest.annotations.Endpoint(DNS.class) @org.jclouds.rest.annotations.Endpoint(DNS.class)
static interface DNSAsyncApi extends Closeable { static interface DNSApi extends Closeable {
@HEAD @HEAD
@Path("/zones/{zoneName}") @Path("/zones/{zoneName}")
@Fallback(FalseOnNotFoundOr404.class) @Fallback(FalseOnNotFoundOr404.class)
public ListenableFuture<Boolean> zoneExists(@PathParam("zoneName") String zoneName); boolean zoneExists(@PathParam("zoneName") String zoneName);
} }
public void testDNSEndpointApplied() { public void testDNSEndpointApplied() {
@ -86,7 +111,7 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
assertTrue(api.zoneExists("foo.com")); assertTrue(api.zoneExists("foo.com"));
} }
private static class DNSApiMetadata extends BaseRestApiMetadata { private static class DNSApiMetadata extends BaseHttpApiMetadata<DNSApi> {
@Override @Override
public Builder toBuilder() { public Builder toBuilder() {
@ -102,31 +127,29 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
} }
public static Properties defaultProperties() { public static Properties defaultProperties() {
Properties properties = BaseRestApiMetadata.defaultProperties(); Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(SERVICE_TYPE, "dns"); properties.setProperty(SERVICE_TYPE, "dns");
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS); properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
return properties; return properties;
} }
public static class Builder extends BaseRestApiMetadata.Builder<Builder> { public static class Builder extends BaseHttpApiMetadata.Builder<DNSApi, Builder> {
protected Builder() { protected Builder() {
super(DNSApi.class, DNSAsyncApi.class);
id("dns") id("dns")
.name("DNS API") .name("DNS API")
.identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant") .identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
.credentialName("${password}") .credentialName("${password}")
.endpointName("Keystone base url ending in /v2.0/") .endpointName("Keystone base url ending in /v2.0/")
.documentation(URI.create("http://dns")) .documentation(URI.create("http://dns"))
.version("1.0") .version("1.0")
.defaultEndpoint("http://localhost:5000/v2.0/") .defaultEndpoint("http://localhost:5000/v2.0/")
.defaultProperties(DNSApiMetadata.defaultProperties()) .defaultProperties(DNSApiMetadata.defaultProperties())
.defaultModules( .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
ImmutableSet.<Class<? extends Module>> builder() .add(AuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class) .add(KeystoneAuthenticationModule.class)
.add(ProviderModule.class) .add(RegionModule.class)
.add(DNSRestClientModule.class) .add(DNSHttpApiModule.class).build());
.build());
} }
@Override @Override