decoupled code that requires async apis from keystone

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

View File

@ -18,47 +18,88 @@
*/
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.openstack.keystone.v2_0.binders.BindAuthToJsonPayload;
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.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.
* <p/>
*
* @see AuthenticationAsyncApi
* @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
*/
public interface AuthenticationApi {
public interface AuthenticationApi extends Closeable {
/**
* Authenticate to generate a 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.
*
* @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.
*
* @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.
*
* @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;
import java.io.Closeable;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
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"
* />
* @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)

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.KeystoneRestClientModule;
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.rest.internal.BaseRestApiMetadata;
@ -90,6 +91,7 @@ public class KeystoneApiMetadata extends BaseRestApiMetadata {
.defaultEndpoint("http://localhost:5000/v${jclouds.api-version}/")
.defaultProperties(KeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(MappedAuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class)
.add(KeystoneAdminURLModule.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;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.rest.config.BinderUtils.bindMappedHttpApi;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
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.implicit.FirstRegion;
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.Endpoint;
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.ZoneIdToURIFromAccessForTypeAndVersion;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@ -89,7 +85,7 @@ public class KeystoneAuthenticationModule extends AbstractModule {
* {@link javax.inject.Qualifier}</li>
* <li>add the above annotation to any {@link AsyncApi} classes by placing it on the type. ex.
* {@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>
* bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
@ -184,12 +180,6 @@ public class KeystoneAuthenticationModule extends AbstractModule {
@Override
protected void configure() {
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;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
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.SERVICE_TYPE;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import static org.testng.Assert.assertTrue;
import java.io.Closeable;
@ -13,6 +32,7 @@ import java.net.URI;
import java.util.Properties;
import javax.inject.Qualifier;
import javax.inject.Singleton;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@ -23,21 +43,23 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.json.config.GsonModule.DateAdapter;
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.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.rest.ConfiguresRestClient;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.annotations.ApiVersion;
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.BaseRestApiMetadata;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import com.google.inject.Provides;
/**
* Tests configuration via {@link ProviderModule}
@ -48,31 +70,34 @@ import com.google.inject.TypeLiteral;
public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModuleExpectTest.DNSApi> {
@Retention(RUNTIME)
@Target(TYPE)
@Target(METHOD)
@Qualifier
static @interface DNS {
}
@ConfiguresRestClient
public static class DNSRestClientModule extends RestClientModule<DNSApi, DNSAsyncApi> {
@ConfiguresHttpApi
public static class DNSHttpApiModule extends HttpApiModule<DNSApi> {
@Override
public void configure() {
bind(new TypeLiteral<Supplier<URI>>() {}).annotatedWith(DNS.class).to(new TypeLiteral<Supplier<URI>>() {});
bind(DateAdapter.class).to(Iso8601DateAdapter.class);
super.configure();
}
}
static interface DNSApi extends Closeable {
boolean zoneExists(@PathParam("zoneName") String zoneName);
@Provides
@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)
static interface DNSAsyncApi extends Closeable {
static interface DNSApi extends Closeable {
@HEAD
@Path("/zones/{zoneName}")
@Fallback(FalseOnNotFoundOr404.class)
public ListenableFuture<Boolean> zoneExists(@PathParam("zoneName") String zoneName);
boolean zoneExists(@PathParam("zoneName") String zoneName);
}
public void testDNSEndpointApplied() {
@ -86,7 +111,7 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
assertTrue(api.zoneExists("foo.com"));
}
private static class DNSApiMetadata extends BaseRestApiMetadata {
private static class DNSApiMetadata extends BaseHttpApiMetadata<DNSApi> {
@Override
public Builder toBuilder() {
@ -102,16 +127,15 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
}
public static Properties defaultProperties() {
Properties properties = BaseRestApiMetadata.defaultProperties();
Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(SERVICE_TYPE, "dns");
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
return properties;
}
public static class Builder extends BaseRestApiMetadata.Builder<Builder> {
public static class Builder extends BaseHttpApiMetadata.Builder<DNSApi, Builder> {
protected Builder() {
super(DNSApi.class, DNSAsyncApi.class);
id("dns")
.name("DNS API")
.identityName("${tenantName}:${userName} or ${userName}, if your keystone supports a default tenant")
@ -121,12 +145,11 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
.version("1.0")
.defaultEndpoint("http://localhost:5000/v2.0/")
.defaultProperties(DNSApiMetadata.defaultProperties())
.defaultModules(
ImmutableSet.<Class<? extends Module>> builder()
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(AuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class)
.add(ProviderModule.class)
.add(DNSRestClientModule.class)
.build());
.add(RegionModule.class)
.add(DNSHttpApiModule.class).build());
}
@Override