Repository: jclouds
Updated Branches:
  refs/heads/master e3d985121 -> 95a3c7ec2


JCLOUDS-646: Copied Cloud Identity v1.1 classes from openstack-common and fixed 
incorrect Keystone package names


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/95a3c7ec
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/95a3c7ec
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/95a3c7ec

Branch: refs/heads/master
Commit: 95a3c7ec2c26edf66da793d0d7a05ef37a58491d
Parents: e3d9851
Author: Jeremy Daggett <[email protected]>
Authored: Thu Jul 31 10:28:33 2014 -0700
Committer: Jeremy Daggett <[email protected]>
Committed: Tue Aug 5 09:01:21 2014 -0700

----------------------------------------------------------------------
 .../cloudidentity/v1_1/AuthenticationApi.java   |  48 +++++
 .../binders/BindCredentialsToJsonPayload.java   |  48 +++++
 .../v1_1/config/Authentication.java             |  31 +++
 .../config/AuthenticationServiceModule.java     | 117 +++++++++++
 .../cloudidentity/v1_1/domain/Auth.java         | 123 ++++++++++++
 .../cloudidentity/v1_1/domain/Endpoint.java     | 198 +++++++++++++++++++
 .../cloudidentity/v1_1/domain/Token.java        | 137 +++++++++++++
 .../v1_1/functions/EndpointToRegion.java        |  27 +++
 .../v1_1/functions/EndpointToSupplierURI.java   |  29 +++
 .../functions/PublicURLOrInternalIfNull.java    |  39 ++++
 .../RegionFirstPartOfDNSNameOrProvider.java     |  47 +++++
 .../v1_1/handlers/RetryOnRenew.java             | 133 +++++++++++++
 ...RegionIdToURIFromAuthForServiceSupplier.java |  67 +++++++
 .../suppliers/V1DefaultRegionIdSupplier.java    |  85 ++++++++
 .../PublicURLOrInternalIfNullTest.java          |  44 +++++
 .../RegionFirstPartOfDNSNameOrProviderTest.java |  48 +++++
 .../v1_1/handlers/RetryOnRenewTest.java         | 166 ++++++++++++++++
 .../BaseKeystoneRestClientExpectTest.java       |  62 ++++++
 .../cloudidentity/v1_1/parse/ParseAuthTest.java |  77 ++++++++
 ...onIdToURIFromAuthForServiceSupplierTest.java |  70 +++++++
 .../V1DefaultRegionIdSupplierTest.java          |  62 ++++++
 .../src/test/resources/auth1_1.json             |  25 +++
 22 files changed, 1683 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/AuthenticationApi.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/AuthenticationApi.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/AuthenticationApi.java
new file mode 100644
index 0000000..a3128fb
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/AuthenticationApi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import 
org.jclouds.rackspace.cloudidentity.v1_1.binders.BindCredentialsToJsonPayload;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.SelectJson;
+
+import com.google.inject.name.Named;
+
+/**
+ * Provides access to the Rackspace Cloud Identity v1.1 API.
+ */
+@Consumes(MediaType.APPLICATION_JSON)
+@Path("/v1.1/auth")
+public interface AuthenticationApi {
+
+   /**
+    * Authenticate to generate a token.
+    *
+    * @return access with token
+    */
+   @Named("authenticate")
+   @POST
+   @SelectJson("auth")
+   @MapBinder(BindCredentialsToJsonPayload.class)
+   Auth authenticate(String username, String key);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/binders/BindCredentialsToJsonPayload.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/binders/BindCredentialsToJsonPayload.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/binders/BindCredentialsToJsonPayload.java
new file mode 100644
index 0000000..d2e6526
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/binders/BindCredentialsToJsonPayload.java
@@ -0,0 +1,48 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.binders;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.rest.MapBinder;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.collect.ImmutableMap;
+
+@Singleton
+public class BindCredentialsToJsonPayload extends BindToJsonPayload implements 
MapBinder {
+   @Inject
+   public BindCredentialsToJsonPayload(Json jsonBinder) {
+      super(jsonBinder);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalStateException("BindCredentialsToJsonPayload needs 
parameters");
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, 
Object> postParams) {
+      return super.bindToRequest(request, ImmutableMap.of("credentials", 
postParams));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/Authentication.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/Authentication.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/Authentication.java
new file mode 100644
index 0000000..ed4fda1
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/Authentication.java
@@ -0,0 +1,31 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, 
ElementType.METHOD })
+@Qualifier
+public @interface Authentication {
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/AuthenticationServiceModule.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/AuthenticationServiceModule.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/AuthenticationServiceModule.java
new file mode 100644
index 0000000..f26d4c2
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/config/AuthenticationServiceModule.java
@@ -0,0 +1,117 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.config;
+
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.location.Provider;
+import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
+import org.jclouds.location.suppliers.RegionIdToURISupplier;
+import org.jclouds.rackspace.cloudidentity.v1_1.AuthenticationApi;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.handlers.RetryOnRenew;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.suppliers.V1DefaultRegionIdSupplier;
+
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import com.google.inject.name.Named;
+
+public class AuthenticationServiceModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      // ServiceClient is used directly for filters and retry handlers, so 
let's bind it explicitly
+      bindHttpApi(binder(), AuthenticationApi.class);
+      install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
+               
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
+      install(new 
FactoryModuleBuilder().implement(ImplicitRegionIdSupplier.class, 
V1DefaultRegionIdSupplier.class)
+               .build(V1DefaultRegionIdSupplier.Factory.class));
+      
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
+   }
+
+   /**
+    * borrowing concurrency code to ensure that caching takes place properly
+    */
+   @Provides
+   @Singleton
+   @Authentication
+   protected Supplier<String> provideAuthenticationTokenCache(final 
Supplier<Auth> supplier)
+            throws InterruptedException, ExecutionException, TimeoutException {
+      return new Supplier<String>() {
+         public String get() {
+            return supplier.get().getToken().getId();
+         }
+      };
+   }
+
+   @Singleton
+   public static class GetAuth extends CacheLoader<Credentials, Auth> {
+
+      private final AuthenticationApi client;
+
+      @Inject
+      public GetAuth(final AuthenticationApi client) {
+         this.client = client;
+      }
+
+      @Override
+      public Auth load(Credentials input) {
+         return client.authenticate(input.identity, input.credential);
+      }
+
+      @Override
+      public String toString() {
+         return "authenticate()";
+      }
+   }
+
+   @Provides
+   @Singleton
+   protected LoadingCache<Credentials, Auth> provideAuthCache(GetAuth getAuth,
+         @Named(PROPERTY_SESSION_INTERVAL) long sessionInterval) {
+      return CacheBuilder.newBuilder().expireAfterWrite(sessionInterval, 
TimeUnit.SECONDS).build(getAuth);
+   }
+
+   @Provides
+   @Singleton
+   protected Supplier<Auth> provideAuthSupplier(final 
LoadingCache<Credentials, Auth> cache,
+         @Provider final Supplier<Credentials> creds) {
+      return new Supplier<Auth>() {
+         @Override
+         public Auth get() {
+            return cache.getUnchecked(creds.get());
+         }
+      };
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Auth.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Auth.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Auth.java
new file mode 100644
index 0000000..04bdba5
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Auth.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.rackspace.cloudidentity.v1_1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Represents an Auth response.
+ */
+public class Auth implements Comparable<Auth> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromAccess(this);
+   }
+
+   public static class Builder {
+      protected Token token;
+      protected Multimap<String, Endpoint> serviceCatalog = 
ImmutableMultimap.of();
+
+      /**
+       * @see Auth#getToken()
+       */
+      public Builder token(Token token) {
+         this.token = checkNotNull(token, "token");
+         return this;
+      }
+
+      /**
+       * @see Auth#getServiceCatalog()
+       */
+      public Builder serviceCatalog(Multimap<String, Endpoint> serviceCatalog) 
{
+         this.serviceCatalog = 
ImmutableMultimap.copyOf(checkNotNull(serviceCatalog, "serviceCatalog"));
+         return this;
+      }
+
+      public Auth build() {
+         return new Auth(token, serviceCatalog);
+      }
+
+      public Builder fromAccess(Auth from) {
+         return 
token(from.getToken()).serviceCatalog(from.getServiceCatalog());
+      }
+   }
+
+   protected final Token token;
+   protected final Multimap<String, Endpoint> serviceCatalog;
+
+   public Auth(Token token, Multimap<String, Endpoint> serviceCatalog) {
+      this.token = checkNotNull(token, "token");
+      this.serviceCatalog = 
ImmutableMultimap.copyOf(checkNotNull(serviceCatalog, "serviceCatalog"));
+   }
+
+   /**
+    * TODO
+    */
+   public Token getToken() {
+      return token;
+   }
+
+   /**
+    * TODO
+    */
+   public Multimap<String, Endpoint> getServiceCatalog() {
+      return serviceCatalog;
+   }
+
+   @Override
+   public boolean equals(Object object) {
+      if (this == object) {
+         return true;
+      }
+      if (object instanceof Auth) {
+         final Auth other = Auth.class.cast(object);
+         return equal(token, other.token) && equal(serviceCatalog, 
other.serviceCatalog);
+      } else {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(token, serviceCatalog);
+   }
+
+   @Override
+   public String toString() {
+      return toStringHelper("").add("token", token).add("serviceCatalog", 
serviceCatalog).toString();
+   }
+
+   @Override
+   public int compareTo(Auth that) {
+      if (that == null)
+         return 1;
+      if (this == that)
+         return 0;
+      return this.token.compareTo(that.token);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Endpoint.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Endpoint.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Endpoint.java
new file mode 100644
index 0000000..020ed85
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Endpoint.java
@@ -0,0 +1,198 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+
+/**
+ * An network-accessible address, usually described by URL, where a service may
+ * be accessed. If using an extension for templates, you can create an endpoint
+ * template, which represents the templates of all the consumable services that
+ * are available across the regions.
+ *
+ */
+public class Endpoint implements Comparable<Endpoint> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromEndpoint(this);
+   }
+
+   public static class Builder {
+
+      protected boolean v1Default;
+      protected String region;
+      protected URI publicURL;
+      protected URI internalURL;
+
+      /**
+       * @see Endpoint#isV1Default()
+       */
+      public Builder v1Default(boolean v1Default) {
+         this.v1Default = v1Default;
+         return this;
+      }
+
+      /**
+       * @see Endpoint#getRegion()
+       */
+      public Builder region(String region) {
+         this.region = checkNotNull(region, "region");
+         return this;
+      }
+
+      /**
+       * @see Endpoint#getPublicURL()
+       */
+      public Builder publicURL(URI publicURL) {
+         this.publicURL = checkNotNull(publicURL, "publicURL");
+         return this;
+      }
+
+      /**
+       * @see Endpoint#getTenantId()
+       */
+      public Builder internalURL(@Nullable URI internalURL) {
+         this.internalURL = internalURL;
+         return this;
+      }
+
+      public Endpoint build() {
+         return new Endpoint(v1Default, region, publicURL, internalURL);
+      }
+
+      public Builder fromEndpoint(Endpoint from) {
+         return 
v1Default(from.isV1Default()).region(from.getRegion()).publicURL(from.getPublicURL())
+               .internalURL(from.getInternalURL());
+      }
+   }
+
+   protected Endpoint() {
+      // we want serializers like Gson to work w/o using sun.misc.Unsafe,
+      // prohibited in GAE. This also implies fields are not final.
+      // see http://code.google.com/p/jclouds/issues/detail?id=925
+   }
+
+   protected boolean v1Default;
+   protected String region;
+   protected URI publicURL;
+   protected URI internalURL;
+
+   protected Endpoint(boolean v1Default, @Nullable String region, @Nullable  
URI publicURL, @Nullable URI internalURL) {
+      this.v1Default = v1Default;
+      this.region = region;
+      this.publicURL = publicURL;
+      this.internalURL = internalURL;
+   }
+
+   /**
+    * The v1Default attribute denotes that an endpoint is being returned in
+    * version 1.0 of the Cloud Authentication Service. The default value of
+    * v1Default is false; clients should assume the value is false when the
+    * attribute is missing. Auth 1.0 does not offer support for regional
+    * endpoints and therefore only returns one endpoint per service. Resources
+    * stored in endpoints where v1Default is false will not be seen by Auth 1.0
+    * clients.
+    *
+    * @return whether this endpoint is visible to v1.0 clients
+    */
+   public boolean isV1Default() {
+      return v1Default;
+   }
+
+   /**
+    * A service may expose endpoints in different regions. Regional endpoints
+    * allow clients to provision resources in a manner that provides high
+    * availability. <br/>
+    * <h3>Note</h3> Some services are not region-specific. These services 
supply
+    * a single non-regional endpoint and do not provide access to internal 
URLs.
+    *
+    * @return the region of the endpoint
+    */
+   @Nullable
+   public String getRegion() {
+      return region;
+   }
+
+   /**
+    * A public URL is accessible from anywhere. Access to a public URL usually 
incurs traffic
+    * charges.
+    *
+    * @return the public endpoint of the service
+    */
+   @Nullable
+   public URI getPublicURL() {
+      return publicURL;
+   }
+
+   /**
+    * Internal URLs are only accessible to services within the same region.
+    * Access to an internal URL is free of charge.
+    *
+    * @return the internal url of the endpoint
+    */
+   @Nullable
+   public URI getInternalURL() {
+      return internalURL;
+   }
+
+   @Override
+   public boolean equals(Object object) {
+      if (this == object) {
+         return true;
+      }
+      if (object instanceof Endpoint) {
+         final Endpoint other = Endpoint.class.cast(object);
+         return equal(v1Default, other.v1Default) && equal(region, 
other.region) && equal(publicURL, other.publicURL)
+               && equal(internalURL, other.internalURL);
+      } else {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(v1Default, region, publicURL, internalURL);
+   }
+
+   @Override
+   public String toString() {
+      return toStringHelper("").add("v1Default", v1Default).add("region", 
region).add("publicURL", publicURL)
+            .add("internalURL", internalURL).toString();
+   }
+
+   @Override
+   public int compareTo(Endpoint that) {
+      if (that == null)
+         return 1;
+      if (this == that)
+         return 0;
+      return this.publicURL.compareTo(that.publicURL);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Token.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Token.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Token.java
new file mode 100644
index 0000000..9d9845b
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/domain/Token.java
@@ -0,0 +1,137 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+
+import com.google.common.base.Objects;
+
+/**
+ * Tokens are valid for a finite duration. The expires attribute denotes the
+ * time after which the token will automatically become invalid. A token may be
+ * manually revoked before the time identified by the expires attribute; 
expires
+ * predicts a token's maximum possible lifespan but does not guarantee that it
+ * will reach that lifespan. Clients are encouraged to cache a token until it
+ * expires.
+ */
+public class Token implements Comparable<Token> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromToken(this);
+   }
+
+   public static class Builder {
+      protected String id;
+      protected Date expires;
+
+      /**
+       * @see Token#getId()
+       */
+      public Builder id(String id) {
+         this.id = checkNotNull(id, "id");
+         return this;
+      }
+
+      /**
+       * @see Token#getExpires()
+       */
+      public Builder expires(Date expires) {
+         this.expires = checkNotNull(expires, "expires");
+         return this;
+      }
+
+      public Token build() {
+         return new Token(id, expires);
+      }
+
+      public Builder fromToken(Token from) {
+         return id(from.getId()).expires(from.getExpires());
+      }
+   }
+
+   protected Token() {
+      // we want serializers like Gson to work w/o using sun.misc.Unsafe,
+      // prohibited in GAE. This also implies fields are not final.
+      // see http://code.google.com/p/jclouds/issues/detail?id=925
+   }
+
+   protected String id;
+   protected Date expires;
+
+   public Token(String id, Date expires) {
+      this.id = checkNotNull(id, "id");
+      this.expires = checkNotNull(expires, "expires");
+   }
+
+   /**
+    * When providing an ID, it is assumed that the token exists in the current
+    * OpenStack deployment
+    *
+    * @return the id of the token in the current OpenStack deployment
+    */
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * @return the expires of the token
+    */
+   public Date getExpires() {
+      return expires;
+   }
+
+   @Override
+   public boolean equals(Object object) {
+      if (this == object) {
+         return true;
+      }
+      if (object instanceof Token) {
+         final Token other = Token.class.cast(object);
+         return equal(id, other.id) && equal(expires, other.expires);
+      } else {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, expires);
+   }
+
+   @Override
+   public String toString() {
+      return toStringHelper("").add("id", id).add("expires", 
expires).toString();
+   }
+
+   @Override
+   public int compareTo(Token that) {
+      if (that == null)
+         return 1;
+      if (this == that)
+         return 0;
+      return this.id.compareTo(that.id);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToRegion.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToRegion.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToRegion.java
new file mode 100644
index 0000000..e75a8f5
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToRegion.java
@@ -0,0 +1,27 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+
+import com.google.common.base.Function;
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(RegionFirstPartOfDNSNameOrProvider.class)
+public interface EndpointToRegion extends Function<Endpoint, String> {
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToSupplierURI.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToSupplierURI.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToSupplierURI.java
new file mode 100644
index 0000000..12d1d2d
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/EndpointToSupplierURI.java
@@ -0,0 +1,29 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import java.net.URI;
+
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(PublicURLOrInternalIfNull.class)
+public interface EndpointToSupplierURI extends Function<Endpoint, 
Supplier<URI>> {
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNull.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNull.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNull.java
new file mode 100644
index 0000000..b4cd7a4
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNull.java
@@ -0,0 +1,39 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
+@Singleton
+public class PublicURLOrInternalIfNull implements EndpointToSupplierURI {
+   // TODO: check accessibility and prioritize private first
+   @Override
+   public Supplier<URI> apply(Endpoint input) {
+      return Suppliers.ofInstance(input.getPublicURL() != null ? 
input.getPublicURL() : input.getInternalURL());
+   }
+
+   public String toString() {
+      return "supplyPublicURL()";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProvider.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProvider.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProvider.java
new file mode 100644
index 0000000..d6ed6b0
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProvider.java
@@ -0,0 +1,47 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.location.Provider;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+
+import com.google.common.net.InternetDomainName;
+
+@Singleton
+public class RegionFirstPartOfDNSNameOrProvider implements EndpointToRegion {
+   private final String provider;
+
+   @Inject
+   RegionFirstPartOfDNSNameOrProvider(@Provider String provider) {
+      this.provider = provider;
+   }
+
+   @Override
+   public String apply(Endpoint input) {
+      if (input.getRegion() != null)
+         return input.getRegion();
+      String host = input.getPublicURL().getHost();
+      if (InternetDomainName.isValid(host)) {
+         InternetDomainName domain = InternetDomainName.from(host);
+         return domain.parts().get(0);
+      }
+      return provider;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenew.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenew.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenew.java
new file mode 100644
index 0000000..5df757a
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenew.java
@@ -0,0 +1,133 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+import static org.jclouds.http.HttpUtils.releasePayload;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import org.jclouds.Constants;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.logging.Logger;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ */
+@Singleton
+public class RetryOnRenew implements HttpRetryHandler {
+   @VisibleForTesting
+   @Inject(optional = true)
+   @Named(Constants.PROPERTY_MAX_RETRIES)
+   static int NUM_RETRIES = 5;
+
+   public final String AUTH_USER = "X-Auth-User";
+   public final String AUTH_KEY = "X-Auth-Key";
+   public final String AUTH_TOKEN = "X-Auth-Token";
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   private final LoadingCache<Credentials, Auth> authenticationResponseCache;
+
+   private final BackoffLimitedRetryHandler backoffHandler;
+
+   @Inject
+   protected RetryOnRenew(LoadingCache<Credentials, Auth> 
authenticationResponseCache,
+           BackoffLimitedRetryHandler backoffHandler) {
+      this.authenticationResponseCache = authenticationResponseCache;
+      this.backoffHandler = backoffHandler;
+   }
+
+   /*
+    * The reason retries need to be tracked is that it is possible that a token
+    * can be expired at any time. The reason we track by request is that only
+    * some requests might return a 401 (such as temporary URLs). However
+    * consistent failures of the magnitude this code tracks should indicate a
+    * problem.
+    */
+   private static final Cache<HttpCommand, Integer> retryCountMap = 
CacheBuilder
+         .newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
+
+   @Override
+   public boolean shouldRetryRequest(HttpCommand command, HttpResponse 
response) {
+      boolean retry = false; // default
+      try {
+         switch (response.getStatusCode()) {
+            case 401:
+               // Do not retry on 401 from authentication request
+               Multimap<String, String> headers = 
command.getCurrentRequest().getHeaders();
+               if (headers != null && headers.containsKey(AUTH_USER)
+                        && headers.containsKey(AUTH_KEY) && 
!headers.containsKey(AUTH_TOKEN)) {
+                  retry = false;
+               } else {
+                  closeClientButKeepContentStream(response);
+                  // This is not an authentication request returning 401
+                  // Check if we already had seen this request
+                  Integer count = retryCountMap.getIfPresent(command);
+
+                  if (count == null) {
+                     // First time this non-authentication request failed
+                     logger.debug("invalidating authentication token - first 
time for %s", command);
+                     retryCountMap.put(command, 1);
+                     authenticationResponseCache.invalidateAll();
+                     retry = true;
+                  } else {
+                     // This request has failed before
+                     if (count + 1 >= NUM_RETRIES) {
+                        logger.debug("too many 401s - giving up after: %s for 
%s", count, command);
+                        retry = false;
+                     } else {
+                        // Retry just in case
+                        logger.debug("invalidating authentication token - 
retry %s for %s", count, command);
+                        retryCountMap.put(command, count + 1);
+                        // Wait between retries
+                        authenticationResponseCache.invalidateAll();
+                        Uninterruptibles.sleepUninterruptibly(5, 
TimeUnit.SECONDS);
+                        retry = true;
+                     }
+                  }
+               }
+               break;
+            case 408:
+               return backoffHandler.shouldRetryRequest(command, response);
+         }
+         return retry;
+
+      } finally {
+         releasePayload(response);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplier.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplier.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplier.java
new file mode 100644
index 0000000..15b655f
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplier.java
@@ -0,0 +1,67 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.suppliers;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.suppliers.RegionIdToURISupplier;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+import org.jclouds.rackspace.cloudidentity.v1_1.functions.EndpointToRegion;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.functions.EndpointToSupplierURI;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.Maps;
+import com.google.inject.assistedinject.Assisted;
+
+@Singleton
+public class RegionIdToURIFromAuthForServiceSupplier implements 
RegionIdToURISupplier {
+
+   private final Supplier<Auth> auth;
+   private final EndpointToSupplierURI endpointToSupplierURI;
+   private final EndpointToRegion endpointToRegion;
+   private final String apiType;
+
+   @Inject
+   public RegionIdToURIFromAuthForServiceSupplier(Supplier<Auth> auth, 
EndpointToSupplierURI endpointToSupplierURI,
+            EndpointToRegion endpointToRegion, @Assisted("apiType") String 
apiType,
+            @Nullable @Assisted("apiVersion") String apiVersion) {
+      this.auth = auth;
+      this.endpointToSupplierURI = endpointToSupplierURI;
+      this.endpointToRegion = endpointToRegion;
+      this.apiType = apiType;
+   }
+
+   @Override
+   public Map<String, Supplier<URI>> get() {
+      Auth authResponse = auth.get();
+      Collection<Endpoint> endpointsForService = 
authResponse.getServiceCatalog().get(apiType);
+      Map<String, Endpoint> regionIdToEndpoint = 
Maps.uniqueIndex(endpointsForService, endpointToRegion);
+      return Maps.transformValues(regionIdToEndpoint, endpointToSupplierURI);
+   }
+
+   @Override
+   public String toString() {
+      return "getPublicURLForService(" + apiType + ")";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplier.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplier.java
 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplier.java
new file mode 100644
index 0000000..5ea0c48
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/main/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplier.java
@@ -0,0 +1,85 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.suppliers;
+
+import static com.google.common.collect.Iterables.tryFind;
+
+import java.util.NoSuchElementException;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+import org.jclouds.rackspace.cloudidentity.v1_1.functions.EndpointToRegion;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.inject.assistedinject.Assisted;
+
+@Singleton
+public class V1DefaultRegionIdSupplier implements ImplicitRegionIdSupplier {
+
+   public interface Factory {
+      /**
+       * 
+       * @param apiType
+       *           type of the api, according to the provider. ex. {@code 
compute}
+       *           {@code object-store}
+       * @return region id
+       * @throws NoSuchElementException
+       *            if the {@code apiType} is not present in the catalog
+       */
+      ImplicitRegionIdSupplier createForApiType(@Assisted("apiType") String 
apiType) throws NoSuchElementException;
+   }
+
+   private final Supplier<Auth> auth;
+   private final EndpointToRegion endpointToRegion;
+   private final String apiType;
+
+   @Inject
+   public V1DefaultRegionIdSupplier(Supplier<Auth> auth, EndpointToRegion 
endpointToRegion,
+            @Assisted("apiType") String apiType) {
+      this.auth = auth;
+      this.endpointToRegion = endpointToRegion;
+      this.apiType = apiType;
+   }
+
+   /**
+    * returns {@link Endpoint#isV1Default()} or first endpoint for service
+    */
+   @Override
+   public String get() {
+      Auth authResponse = auth.get();
+      Iterable<Endpoint> endpointsForService = 
authResponse.getServiceCatalog().get(apiType);
+      Optional<Endpoint> defaultEndpoint = tryFind(endpointsForService, new 
Predicate<Endpoint>() {
+         @Override
+         public boolean apply(Endpoint in) {
+            return in.isV1Default();
+         }
+      });
+      return 
endpointToRegion.apply(defaultEndpoint.or(Iterables.get(endpointsForService, 
0)));
+   }
+
+   @Override
+   public String toString() {
+      return "defaultRegionIdFor(" + apiType + ")";
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNullTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNullTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNullTest.java
new file mode 100644
index 0000000..9370d2b
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/PublicURLOrInternalIfNullTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.functions.PublicURLOrInternalIfNull;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "PublicURLOrInternalIfNullTest")
+public class PublicURLOrInternalIfNullTest {
+   private final PublicURLOrInternalIfNull fn = new 
PublicURLOrInternalIfNull();
+
+   public void testPublicURLNotNullReturnsPublicURL() {
+      assertEquals(fn.apply(
+               Endpoint.builder().region("LON").publicURL(
+                        
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+                        .v1Default(true).build()).get(), URI
+               
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";));
+   }
+
+   public void testPublicURLNullReturnsInternalURL() {
+      
assertEquals(fn.apply(Endpoint.builder().internalURL(URI.create("https://192.168.1.1";)).v1Default(true).build())
+               .get(), URI.create("https://192.168.1.1";));
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProviderTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProviderTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProviderTest.java
new file mode 100644
index 0000000..7b336ad
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/functions/RegionFirstPartOfDNSNameOrProviderTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.functions.RegionFirstPartOfDNSNameOrProvider;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "RegionFirstPartOfDNSNameOrProviderTest")
+public class RegionFirstPartOfDNSNameOrProviderTest {
+   private final RegionFirstPartOfDNSNameOrProvider fn = new 
RegionFirstPartOfDNSNameOrProvider("keystone");
+
+   public void testRegionNotNullReturnsRegion() {
+      assertEquals(fn.apply(Endpoint.builder().region("LON").publicURL(
+               
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+               .v1Default(true).build()), "LON");
+   }
+
+   public void testRegionNullReturnsFirstPartOfHostWhenValid() {
+      assertEquals(fn.apply(Endpoint.builder().publicURL(
+               
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+               .v1Default(true).build()), "cdn3");
+   }
+
+   public void testRegionNullReturnsProvioderWhenHostNotValid() {
+      
assertEquals(fn.apply(Endpoint.builder().publicURL(URI.create("https://1.1.1.4";)).v1Default(true).build()),
+               "keystone");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenewTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenewTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenewTest.java
new file mode 100644
index 0000000..17fa2fc
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/handlers/RetryOnRenewTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.handlers;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.io.Payloads;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.handlers.RetryOnRenew;
+import org.testng.annotations.Test;
+
+import com.google.common.cache.LoadingCache;
+
+/**
+ * Tests behavior of {@code RetryOnRenew} handler
+ */
+@Test(groups = "unit", testName = "RetryOnRenewTest")
+public class RetryOnRenewTest {
+   @Test
+   public void test401ShouldRetry() {
+      HttpCommand command = createMock(HttpCommand.class);
+      HttpRequest request = createMock(HttpRequest.class);
+      HttpResponse response = createMock(HttpResponse.class);
+      @SuppressWarnings("unchecked")
+      LoadingCache<Credentials, Auth> cache = createMock(LoadingCache.class);
+      BackoffLimitedRetryHandler backoffHandler = 
createMock(BackoffLimitedRetryHandler.class);
+
+      expect(command.getCurrentRequest()).andReturn(request);
+
+      cache.invalidateAll();
+      expectLastCall();
+
+      expect(response.getPayload()).andReturn(Payloads.newStringPayload("token 
expired, please renew")).anyTimes();
+      expect(response.getStatusCode()).andReturn(401).atLeastOnce();
+
+      replay(command);
+      replay(response);
+      replay(cache);
+      replay(backoffHandler);
+
+      RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);
+
+      assertTrue(retry.shouldRetryRequest(command, response));
+
+      verify(command);
+      verify(response);
+      verify(cache);
+      verify(backoffHandler);
+   }
+
+   @Test
+   public void test401ShouldRetry4Times() {
+      HttpCommand command = createMock(HttpCommand.class);
+      HttpRequest request = createMock(HttpRequest.class);
+      HttpResponse response = createMock(HttpResponse.class);
+
+      @SuppressWarnings("unchecked")
+      LoadingCache<Credentials, Auth> cache = createMock(LoadingCache.class);
+      BackoffLimitedRetryHandler backoffHandler = 
createMock(BackoffLimitedRetryHandler.class);
+
+      expect(command.getCurrentRequest()).andReturn(request).anyTimes();
+      expect(request.getHeaders()).andStubReturn(null);
+
+      cache.invalidateAll();
+      expectLastCall().anyTimes();
+
+      expect(response.getPayload()).andReturn(Payloads.newStringPayload(""))
+            .anyTimes();
+      expect(response.getStatusCode()).andReturn(401).anyTimes();
+
+      replay(command, request, response, cache);
+
+      RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);
+
+      for (int i = 0; i < RetryOnRenew.NUM_RETRIES - 1; ++i) {
+         assertTrue(retry.shouldRetryRequest(command, response),
+               "Expected retry to succeed");
+      }
+
+      assertFalse(retry.shouldRetryRequest(command, response),
+            "Expected retry to fail on attempt " + RetryOnRenew.NUM_RETRIES);
+
+      verify(command, response, cache);
+   }
+
+   @Test
+   public void test408ShouldRetry() {
+      HttpCommand command = createMock(HttpCommand.class);
+      HttpRequest request = createMock(HttpRequest.class);
+      HttpResponse response = createMock(HttpResponse.class);
+      @SuppressWarnings("unchecked")
+      LoadingCache<Credentials, Auth> cache = createMock(LoadingCache.class);
+      BackoffLimitedRetryHandler backoffHandler = 
createMock(BackoffLimitedRetryHandler.class);
+
+      expect(response.getPayload()).andReturn(Payloads.newStringPayload(
+                  "The server has waited too long for the request to be sent 
by the client.")).times(2);
+      expect(backoffHandler.shouldRetryRequest(command, 
response)).andReturn(true).once();
+      expect(response.getStatusCode()).andReturn(408).once();
+
+      replay(command);
+      replay(response);
+      replay(cache);
+      replay(backoffHandler);
+
+      RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);
+
+      assertTrue(retry.shouldRetryRequest(command, response));
+
+      verify(command);
+      verify(response);
+      verify(cache);
+      verify(backoffHandler);
+   }
+
+   @Test
+   public void test404ShouldNotRetry() {
+      HttpCommand command = createMock(HttpCommand.class);
+      HttpRequest request = createMock(HttpRequest.class);
+      HttpResponse response = createMock(HttpResponse.class);
+      @SuppressWarnings("unchecked")
+      LoadingCache<Credentials, Auth> cache = createMock(LoadingCache.class);
+      BackoffLimitedRetryHandler backoffHandler = 
createMock(BackoffLimitedRetryHandler.class);
+
+      
expect(response.getPayload()).andReturn(Payloads.newStringPayload("")).times(2);
+      expect(response.getStatusCode()).andReturn(404).once();
+
+      replay(command);
+      replay(response);
+      replay(cache);
+      replay(backoffHandler);
+
+      RetryOnRenew retry = new RetryOnRenew(cache, backoffHandler);
+
+      assertTrue(!retry.shouldRetryRequest(command, response));
+
+      verify(command);
+      verify(response);
+      verify(cache);
+      verify(backoffHandler);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/internal/BaseKeystoneRestClientExpectTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/internal/BaseKeystoneRestClientExpectTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/internal/BaseKeystoneRestClientExpectTest.java
new file mode 100644
index 0000000..4638c3e
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/internal/BaseKeystoneRestClientExpectTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.internal;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.config.AuthenticationServiceModule;
+import org.jclouds.rest.internal.BaseRestClientExpectTest;
+
+import com.google.common.net.HttpHeaders;
+
+/**
+ * Base class for writing KeyStone Rest Client Expect tests
+ */
+public class BaseKeystoneRestClientExpectTest<S> extends 
BaseRestClientExpectTest<S> {
+
+   protected String endpoint = "http://localhost:5000";;
+
+   public BaseKeystoneRestClientExpectTest() {
+      identity = "[email protected]";
+      credential = "Password1234";
+   }
+
+   protected HttpRequest initialAuth = HttpRequest.builder().method("POST")
+         .endpoint(endpoint + "/v1.1/auth")
+         .addHeader(HttpHeaders.ACCEPT, "application/json")
+         .payload(
+               payloadFromStringWithContentType(
+                     
"{\"credentials\":{\"username\":\"[email protected]\",\"key\":\"Password1234\"}}",
+                     "application/json")).build();
+
+   protected String authToken = "118fb907-0786-4799-88f0-9a5b7963d1ab";
+
+   protected HttpResponse responseWithAuth = 
HttpResponse.builder().statusCode(200).message("HTTP/1.1 200")
+         .payload(payloadFromResourceWithContentType("/auth1_1.json", 
"application/json")).build();
+
+   /**
+    * in case you need to override anything
+    */
+   public static class TestKeystoneAuthenticationModule extends 
AuthenticationServiceModule {
+      @Override
+      protected void configure() {
+         super.configure();
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/parse/ParseAuthTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/parse/ParseAuthTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/parse/ParseAuthTest.java
new file mode 100644
index 0000000..7d8518a
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/parse/ParseAuthTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.date.internal.SimpleDateFormatDateService;
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Endpoint;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Token;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+
+@Test(groups = "unit", testName = "ParseAuthTest")
+public class ParseAuthTest extends BaseItemParserTest<Auth> {
+
+   @Override
+   public String resource() {
+      return "/auth1_1.json";
+   }
+
+   @Override
+   @SelectJson("auth")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Auth expected() {
+      return Auth
+            .builder()
+            .token(
+                  Token.builder()
+                        .expires(new 
SimpleDateFormatDateService().iso8601DateParse("2012-01-30T02:30:54.000-06:00"))
+                        .id("118fb907-0786-4799-88f0-9a5b7963d1ab").build())
+            .serviceCatalog(
+                  ImmutableMultimap.of(
+                        "cloudFilesCDN",
+                        Endpoint
+                              .builder()
+                              .region("LON")
+                              .publicURL(
+                                    
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+                              .v1Default(true).build(),
+                        "cloudFiles",
+                        Endpoint
+                              .builder()
+                              .region("LON")
+                              .publicURL(
+                                    
URI.create("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+                              .v1Default(true)
+                              .internalURL(
+                                    
URI.create("https://snet-storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";))
+                              .build(),
+                        "cloudServers",
+                        Endpoint.builder()
+                              
.publicURL(URI.create("https://lon.servers.api.rackspacecloud.com/v1.0/10001786";))
+                              .v1Default(true).build())).build();
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplierTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplierTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplierTest.java
new file mode 100644
index 0000000..3578771
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/RegionIdToURIFromAuthForServiceSupplierTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.suppliers;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.location.Provider;
+import org.jclouds.location.suppliers.RegionIdToURISupplier;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.parse.ParseAuthTest;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.suppliers.RegionIdToURIFromAuthForServiceSupplier;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Provides;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+
+@Test(groups = "unit", testName = 
"RegionIdToURIFromAuthForServiceSupplierTest")
+public class RegionIdToURIFromAuthForServiceSupplierTest {
+   private final RegionIdToURISupplier.Factory factory = 
Guice.createInjector(new AbstractModule() {
+
+      @Override
+      protected void configure() {
+         bindConstant().annotatedWith(Provider.class).to("keystone");
+         install(new 
FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
+                  
RegionIdToURIFromAuthForServiceSupplier.class).build(RegionIdToURISupplier.Factory.class));
+      }
+
+      @Provides
+      @Singleton
+      public Supplier<Auth> provide() {
+         return Suppliers.ofInstance(new ParseAuthTest().expected());
+      }
+   }).getInstance(RegionIdToURISupplier.Factory.class);
+
+   public void testRegionMatches() {
+      
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("cloudFilesCDN",
 "1.0").get(), Suppliers
+               .<URI> supplierFunction()), ImmutableMap.of("LON", URI
+               
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953";)));
+   }
+
+   public void testTakesFirstPartOfDNSWhenNoRegion() {
+      
assertEquals(Maps.transformValues(factory.createForApiTypeAndVersion("cloudServers",
 "1.1").get(), Suppliers
+               .<URI> supplierFunction()), ImmutableMap.of("lon", URI
+               
.create("https://lon.servers.api.rackspacecloud.com/v1.0/10001786";)));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplierTest.java
----------------------------------------------------------------------
diff --git 
a/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplierTest.java
 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplierTest.java
new file mode 100644
index 0000000..6325833
--- /dev/null
+++ 
b/apis/rackspace-cloudidentity/src/test/java/org/jclouds/rackspace/cloudidentity/v1_1/suppliers/V1DefaultRegionIdSupplierTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rackspace.cloudidentity.v1_1.suppliers;
+
+import static org.testng.Assert.assertEquals;
+
+import javax.inject.Singleton;
+
+import org.jclouds.location.Provider;
+import org.jclouds.location.suppliers.ImplicitRegionIdSupplier;
+import org.jclouds.rackspace.cloudidentity.v1_1.domain.Auth;
+import org.jclouds.rackspace.cloudidentity.v1_1.parse.ParseAuthTest;
+import 
org.jclouds.rackspace.cloudidentity.v1_1.suppliers.V1DefaultRegionIdSupplier;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Provides;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+
+@Test(groups = "unit", testName = "V1DefaultRegionIdSupplierTest")
+public class V1DefaultRegionIdSupplierTest {
+   private final V1DefaultRegionIdSupplier.Factory factory = 
Guice.createInjector(new AbstractModule() {
+
+      @Override
+      protected void configure() {
+         bindConstant().annotatedWith(Provider.class).to("keystone");
+         install(new 
FactoryModuleBuilder().implement(ImplicitRegionIdSupplier.class, 
V1DefaultRegionIdSupplier.class)
+                  .build(V1DefaultRegionIdSupplier.Factory.class));
+      }
+
+      @Provides
+      @Singleton
+      public Supplier<Auth> provide() {
+         return Suppliers.ofInstance(new ParseAuthTest().expected());
+      }
+   }).getInstance(V1DefaultRegionIdSupplier.Factory.class);
+
+   public void testRegionMatches() {
+      assertEquals(factory.createForApiType("cloudFilesCDN").get(), "LON");
+   }
+
+   public void testTakesFirstPartOfDNSWhenNoRegion() {
+      assertEquals(factory.createForApiType("cloudServers").get(), "lon");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/95a3c7ec/apis/rackspace-cloudidentity/src/test/resources/auth1_1.json
----------------------------------------------------------------------
diff --git a/apis/rackspace-cloudidentity/src/test/resources/auth1_1.json 
b/apis/rackspace-cloudidentity/src/test/resources/auth1_1.json
new file mode 100644
index 0000000..545adbd
--- /dev/null
+++ b/apis/rackspace-cloudidentity/src/test/resources/auth1_1.json
@@ -0,0 +1,25 @@
+{
+    "auth": {
+        "token": {
+            "id": "118fb907-0786-4799-88f0-9a5b7963d1ab",
+            "expires": "2012-01-30T02:30:54.000-06:00"
+        },
+        "serviceCatalog": {
+            "cloudFilesCDN": [{
+                "region": "LON",
+                "publicURL": 
"https:\/\/cdn3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
+                "v1Default": true
+            }],
+            "cloudFiles": [{
+                "region": "LON",
+                "publicURL": 
"https:\/\/storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953",
+                "v1Default": true,
+                "internalURL": 
"https:\/\/snet-storage101.lon3.clouddrive.com\/v1\/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"
+            }],
+            "cloudServers": [{
+                "publicURL": 
"https:\/\/lon.servers.api.rackspacecloud.com\/v1.0\/10001786",
+                "v1Default": true
+            }]
+        }
+    }
+}

Reply via email to