JCLOUDS-458: Added Blobstore Abstraction

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

Branch: refs/heads/1.8.x
Commit: ccc2d243a17648fedd724e27725cd9cf58db7883
Parents: d97a0c4
Author: hsbhathiya <[email protected]>
Authored: Tue Sep 2 01:46:54 2014 +0530
Committer: Andrew Gaul <[email protected]>
Committed: Wed Sep 10 15:04:42 2014 -0700

----------------------------------------------------------------------
 .../GoogleCloudStorageApiMetadata.java          |  27 +-
 .../blobstore/GCSAsyncBlobStore.java            | 289 +++++++++++++++++++
 .../blobstore/GCSBlobStore.java                 | 273 ++++++++++++++++++
 .../config/GCSBlobStoreContextModule.java       |  35 +++
 .../functions/BlobMetadataToObjectTemplate.java |  57 ++++
 ...ListContainerOptionsToListObjectOptions.java |  50 ++++
 .../functions/BucketToStorageMetadata.java      |  47 +++
 .../functions/ObjectListToStorageMetadata.java  |  65 +++++
 .../functions/ObjectToBlobMetadata.java         |  79 +++++
 .../internal/MultipartNamingStrategy.java       |  30 ++
 .../strategy/internal/MultipartUpload.java      |  36 +++
 .../MultipartUploadSlicingAlgorithm.java        | 138 +++++++++
 .../internal/MultipartUploadStrategy.java       |  26 ++
 .../SequentialMultipartUploadStrategy.java      | 106 +++++++
 .../config/GoogleCloudStorageHttpApiModule.java |  41 +++
 .../googlecloudstorage/config/UserProject.java  |  33 +++
 .../googlecloudstorage/domain/Bucket.java       |   4 +-
 .../domain/BucketAccessControls.java            |   2 +-
 .../domain/DefaultObjectAccessControls.java     |   2 +-
 .../domain/DomainResourceReferences.java        | 105 +++++++
 .../domain/DomainResourceRefferences.java       | 105 -------
 .../googlecloudstorage/domain/GCSObject.java    |  17 +-
 .../domain/ObjectAccessControls.java            |   2 +-
 .../domain/templates/BucketTemplate.java        |   4 +-
 .../DefaultObjectAccessControlsTemplate.java    |   2 +-
 .../templates/ObjectAccessControlsTemplate.java |   2 +-
 .../domain/templates/ObjectTemplate.java        |  14 +-
 .../fallback/GCSFallbacks.java                  |  39 +++
 .../googlecloudstorage/features/BucketApi.java  |  30 +-
 .../DefaultObjectAccessControlsApi.java         |   2 +-
 .../googlecloudstorage/features/ObjectApi.java  |   4 +
 .../options/ComposeObjectOptions.java           |   2 +-
 .../options/CopyObjectOptions.java              |   4 +-
 .../options/DeleteObjectOptions.java            |   2 +-
 .../options/GetBucketOptions.java               |   2 +-
 .../options/GetObjectOptions.java               |   2 +-
 .../options/InsertBucketOptions.java            |   4 +-
 .../options/InsertObjectOptions.java            |   4 +-
 .../options/ListObjectOptions.java              |   2 +-
 .../googlecloudstorage/options/ListOptions.java |   2 +-
 .../options/UpdateBucketOptions.java            |   4 +-
 .../options/UpdateObjectOptions.java            |   4 +-
 .../reference/GoogleCloudStorageConstants.java  |   7 +
 .../integration/GCSBlobIntegrationLiveTest.java | 260 +++++++++++++++++
 .../blobstore/integration/GCSBlobLiveTest.java  | 108 +++++++
 .../GCSContainerIntegrationLiveTest.java        |  97 +++++++
 .../integration/GCSContainerLiveTest.java       |  28 ++
 .../BucketAccessControlsApiExpectTest.java      |   2 +-
 .../BucketAccessControlsApiLiveTest.java        |   2 +-
 .../features/BucketApiExpectTest.java           |   4 +-
 .../features/BucketApiLiveTest.java             |  25 +-
 ...efaultObjectAccessControlsApiExpectTest.java |   2 +-
 .../DefaultObjectAccessControlsApiLiveTest.java |   2 +-
 .../ObjectAccessControlsApiExpectTest.java      |   2 +-
 .../features/ObjectApiLiveTest.java             |   6 +-
 .../features/ResumableUploadApiLiveTest.java    |   2 +-
 .../parse/BucketAclGetTest.java                 |   2 +-
 .../parse/BucketAclInsertTest.java              |   2 +-
 .../parse/BucketAclListTest.java                |   2 +-
 .../parse/BucketAclUpdateTest.java              |   2 +-
 .../parse/BucketUpdateTest.java                 |   4 +-
 .../parse/DefaultObjectAclGetTest.java          |   2 +-
 .../parse/DefaultObjectAclInsertTest.java       |   2 +-
 .../parse/DefaultObjectAclListTest.java         |   2 +-
 .../parse/FullBucketGetTest.java                |   8 +-
 .../parse/NoAclBucketListTest.java              |   4 +-
 .../parse/NoAclBucketTest.java                  |   4 +-
 .../parse/ObjectAclGetTest.java                 |   2 +-
 .../parse/ObjectAclInsertTest.java              |   2 +-
 .../parse/ObjectAclListTest.java                |   2 +-
 .../parse/ObjectAclUpdateTest.java              |   2 +-
 71 files changed, 2086 insertions(+), 201 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/GoogleCloudStorageApiMetadata.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/GoogleCloudStorageApiMetadata.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/GoogleCloudStorageApiMetadata.java
index 741088c..f88541c 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/GoogleCloudStorageApiMetadata.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/GoogleCloudStorageApiMetadata.java
@@ -26,7 +26,9 @@ import static org.jclouds.reflect.Reflection2.typeToken;
 
 import java.net.URI;
 import java.util.Properties;
+
 import org.jclouds.blobstore.BlobStoreContext;
+import 
org.jclouds.googlecloudstorage.blobstore.config.GCSBlobStoreContextModule;
 import org.jclouds.googlecloudstorage.config.GoogleCloudStorageHttpApiModule;
 import org.jclouds.googlecloudstorage.config.GoogleCloudStorageParserModule;
 import org.jclouds.googlecloudstorage.config.OAuthModuleWithoutTypeAdapters;
@@ -65,18 +67,19 @@ public class GoogleCloudStorageApiMetadata extends 
BaseHttpApiMetadata<GoogleClo
    public static class Builder extends 
BaseHttpApiMetadata.Builder<GoogleCloudStorageApi, Builder> {
       protected Builder() {
          id(GCS_PROVIDER_NAME)
-               .name("Google Cloud Storage Api ")
-               .identityName("Email associated with the Google API client_id")
-               .credentialName("Private key literal associated with the Google 
API client_id")
-               
.documentation(URI.create("https://developers.google.com/storage/docs/json_api";))
-               .version("v1")
-               .defaultEndpoint("https://www.googleapis.com";)
-               
.defaultProperties(GoogleCloudStorageApiMetadata.defaultProperties())
-               .view(typeToken(BlobStoreContext.class))
-               .defaultModules(
-                     ImmutableSet.<Class<? extends Module>> 
builder().add(GoogleCloudStorageParserModule.class)
-                           
.add(OAuthAuthenticationModule.class).add(OAuthModuleWithoutTypeAdapters.class)
-                           
.add(GoogleCloudStorageHttpApiModule.class).build());
+                  .name("Google Cloud Storage Api ")
+                  .identityName("Email associated with the Google API 
client_id")
+                  .credentialName("Private key literal associated with the 
Google API client_id")
+                  
.documentation(URI.create("https://developers.google.com/storage/docs/json_api";))
+                  .version("v1")
+                  .defaultEndpoint("https://www.googleapis.com";)
+                  
.defaultProperties(GoogleCloudStorageApiMetadata.defaultProperties())
+                  .view(typeToken(BlobStoreContext.class))
+                  .defaultModules(
+                           ImmutableSet.<Class<? extends Module>> 
of(GoogleCloudStorageParserModule.class,
+                                    OAuthAuthenticationModule.class, 
OAuthModuleWithoutTypeAdapters.class,
+                                    GoogleCloudStorageHttpApiModule.class, 
GCSBlobStoreContextModule.class));
+
       }
 
       @Override

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSAsyncBlobStore.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSAsyncBlobStore.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSAsyncBlobStore.java
new file mode 100644
index 0000000..955cf9b
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSAsyncBlobStore.java
@@ -0,0 +1,289 @@
+/*
+ * 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.googlecloudstorage.blobstore;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.inject.Singleton;
+
+import org.jclouds.blobstore.AsyncBlobStore;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.BlobBuilder;
+import org.jclouds.blobstore.domain.BlobMetadata;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.options.CreateContainerOptions;
+import org.jclouds.blobstore.options.GetOptions;
+import org.jclouds.blobstore.options.ListContainerOptions;
+import org.jclouds.blobstore.options.PutOptions;
+import org.jclouds.domain.Location;
+
+import com.google.common.collect.ForwardingObject;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+@SuppressWarnings("deprecation")
+@Singleton
+public class GCSAsyncBlobStore extends ForwardingObject implements 
AsyncBlobStore {
+   private final BlobStore blobstore;
+   private final ListeningExecutorService executor;
+
+   @Inject
+   public GCSAsyncBlobStore(BlobStore blobstore, @Named(PROPERTY_USER_THREADS) 
ListeningExecutorService executor) {
+      this.blobstore = checkNotNull(blobstore, "blobstore");
+      this.executor = checkNotNull(executor, "executor");
+   }
+
+   @Override
+   public BlobStoreContext getContext() {
+      return delegate().getContext();
+   }
+
+   @Override
+   public BlobBuilder blobBuilder(String name) {
+      return delegate().blobBuilder(name);
+   }
+
+   @Override
+   public ListenableFuture<Set<? extends Location>> listAssignableLocations() {
+      return executor.submit(new Callable<Set<? extends Location>>() {
+         public Set<? extends Location> call() {
+            return delegate().listAssignableLocations();
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
+      return executor.submit(new Callable<PageSet<? extends 
StorageMetadata>>() {
+         public PageSet<? extends StorageMetadata> call() {
+            return delegate().list();
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> containerExists(final String container) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().containerExists(container);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> createContainerInLocation(final Location 
location, final String container) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().createContainerInLocation(location, container);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> createContainerInLocation(final Location 
location, final String container,
+            final CreateContainerOptions options) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().createContainerInLocation(location, container, 
options);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<PageSet<? extends StorageMetadata>> list(final 
String container) {
+      return executor.submit(new Callable<PageSet<? extends 
StorageMetadata>>() {
+         public PageSet<? extends StorageMetadata> call() {
+            return delegate().list(container);
+         }
+      });
+
+   }
+
+   @Override
+   public ListenableFuture<PageSet<? extends StorageMetadata>> list(final 
String container,
+            final ListContainerOptions options) {
+      return executor.submit(new Callable<PageSet<? extends 
StorageMetadata>>() {
+         public PageSet<? extends StorageMetadata> call() {
+            return delegate().list(container, options);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> clearContainer(final String container) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().clearContainer(container);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> clearContainer(final String container, final 
ListContainerOptions options) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().clearContainer(container, options);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> deleteContainer(final String container) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().deleteContainer(container);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> deleteContainerIfEmpty(final String 
container) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().deleteContainerIfEmpty(container);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> directoryExists(final String container, 
final String directory) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().directoryExists(container, directory);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> createDirectory(final String container, final 
String directory) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().createDirectory(container, directory);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> deleteDirectory(final String containerName, 
final String name) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().deleteDirectory(containerName, name);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Boolean> blobExists(final String container, final 
String name) {
+      return executor.submit(new Callable<Boolean>() {
+         public Boolean call() {
+            return delegate().blobExists(container, name);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<String> putBlob(final String container, final Blob 
blob) {
+      return executor.submit(new Callable<String>() {
+         public String call() {
+            return delegate().putBlob(container, blob);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<String> putBlob(final String container, final Blob 
blob, final PutOptions options) {
+      return executor.submit(new Callable<String>() {
+         public String call() {
+            return delegate().putBlob(container, blob, options);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<BlobMetadata> blobMetadata(final String container, 
final String key) {
+      return executor.submit(new Callable<BlobMetadata>() {
+         public BlobMetadata call() {
+            return delegate().blobMetadata(container, key);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Blob> getBlob(final String container, final String 
key) {
+      return executor.submit(new Callable<Blob>() {
+         public Blob call() {
+            return delegate().getBlob(container, key);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Blob> getBlob(final String container, final String 
key, final GetOptions options) {
+      return executor.submit(new Callable<Blob>() {
+         public Blob call() {
+            return delegate().getBlob(container, key, options);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Void> removeBlob(final String container, final 
String key) {
+      return executor.submit(new Callable<Void>() {
+         public Void call() {
+            delegate().removeBlob(container, key);
+            return null;
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Long> countBlobs(final String container) {
+      return executor.submit(new Callable<Long>() {
+         public Long call() {
+            return delegate().countBlobs(container);
+         }
+      });
+   }
+
+   @Override
+   public ListenableFuture<Long> countBlobs(final String container, final 
ListContainerOptions options) {
+      return executor.submit(new Callable<Long>() {
+         public Long call() {
+            return delegate().countBlobs(container, options);
+         }
+      });
+   }
+
+   @Override
+   protected BlobStore delegate() {
+      return blobstore;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSBlobStore.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSBlobStore.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSBlobStore.java
new file mode 100644
index 0000000..e0d433c
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GCSBlobStore.java
@@ -0,0 +1,273 @@
+/*
+ * 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.googlecloudstorage.blobstore;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.BlobMetadata;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.internal.BlobBuilderImpl;
+import org.jclouds.blobstore.domain.internal.PageSetImpl;
+import org.jclouds.blobstore.internal.BaseBlobStore;
+import org.jclouds.blobstore.options.CreateContainerOptions;
+import org.jclouds.blobstore.options.ListContainerOptions;
+import org.jclouds.blobstore.options.PutOptions;
+import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
+import org.jclouds.blobstore.util.BlobUtils;
+import org.jclouds.collect.Memoized;
+import org.jclouds.domain.Location;
+import org.jclouds.googlecloudstorage.GoogleCloudStorageApi;
+import 
org.jclouds.googlecloudstorage.blobstore.functions.BlobMetadataToObjectTemplate;
+import 
org.jclouds.googlecloudstorage.blobstore.functions.BlobStoreListContainerOptionsToListObjectOptions;
+import 
org.jclouds.googlecloudstorage.blobstore.functions.BucketToStorageMetadata;
+import 
org.jclouds.googlecloudstorage.blobstore.functions.ObjectListToStorageMetadata;
+import org.jclouds.googlecloudstorage.blobstore.functions.ObjectToBlobMetadata;
+import 
org.jclouds.googlecloudstorage.blobstore.strategy.internal.MultipartUploadStrategy;
+import org.jclouds.googlecloudstorage.config.UserProject;
+import org.jclouds.googlecloudstorage.domain.Bucket;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.ObjectRole;
+import org.jclouds.googlecloudstorage.domain.GCSObject;
+import org.jclouds.googlecloudstorage.domain.ListPage;
+import org.jclouds.googlecloudstorage.domain.templates.BucketTemplate;
+import 
org.jclouds.googlecloudstorage.domain.templates.DefaultObjectAccessControlsTemplate;
+import org.jclouds.googlecloudstorage.domain.templates.ObjectTemplate;
+import org.jclouds.googlecloudstorage.options.ListObjectOptions;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.http.internal.PayloadEnclosingImpl;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import com.google.common.hash.HashCode;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+@Singleton
+public class GCSBlobStore extends BaseBlobStore {
+
+   GoogleCloudStorageApi api;
+   BucketToStorageMetadata bucketToStorageMetadata;
+   ObjectToBlobMetadata objectToBlobMetadata;
+   ObjectListToStorageMetadata objectListToStorageMetadata;
+   Provider<FetchBlobMetadata> fetchBlobMetadataProvider;
+   BlobMetadataToObjectTemplate blobMetadataToObjectTemplate;
+   BlobStoreListContainerOptionsToListObjectOptions 
listContainerOptionsToListObjectOptions;
+   MultipartUploadStrategy multipartUploadStrategy;
+   Supplier<String> projectId;
+
+   @Inject
+   protected GCSBlobStore(BlobStoreContext context, BlobUtils blobUtils, 
Supplier<Location> defaultLocation,
+            @Memoized Supplier<Set<? extends Location>> locations, 
GoogleCloudStorageApi api,
+            BucketToStorageMetadata bucketToStorageMetadata, 
ObjectToBlobMetadata objectToBlobMetadata,
+            ObjectListToStorageMetadata objectListToStorageMetadata,
+            Provider<FetchBlobMetadata> fetchBlobMetadataProvider,
+            BlobMetadataToObjectTemplate blobMetadataToObjectTemplate,
+            BlobStoreListContainerOptionsToListObjectOptions 
listContainerOptionsToListObjectOptions,
+            MultipartUploadStrategy multipartUploadStrategy, @UserProject 
Supplier<String> projectId) {
+      super(context, blobUtils, defaultLocation, locations);
+      this.api = api;
+      this.bucketToStorageMetadata = bucketToStorageMetadata;
+      this.objectToBlobMetadata = objectToBlobMetadata;
+      this.objectListToStorageMetadata = objectListToStorageMetadata;
+      this.fetchBlobMetadataProvider = checkNotNull(fetchBlobMetadataProvider, 
"fetchBlobMetadataProvider");
+      this.blobMetadataToObjectTemplate = blobMetadataToObjectTemplate;
+      this.listContainerOptionsToListObjectOptions = 
listContainerOptionsToListObjectOptions;
+      this.projectId = projectId;
+      this.multipartUploadStrategy = multipartUploadStrategy;
+   }
+
+   @Override
+   public PageSet<? extends StorageMetadata> list() {
+      return new Function<ListPage<Bucket>, 
org.jclouds.blobstore.domain.PageSet<? extends StorageMetadata>>() {
+         public org.jclouds.blobstore.domain.PageSet<? extends 
StorageMetadata> apply(ListPage<Bucket> from) {
+            return new PageSetImpl<StorageMetadata>(Iterables.transform(from, 
bucketToStorageMetadata), null);
+         }
+      }.apply(api.getBucketApi().listBucket(projectId.get()));
+   }
+
+   @Override
+   public boolean containerExists(String container) {
+      return api.getBucketApi().bucketExist(container);
+   }
+
+   @Override
+   public boolean createContainerInLocation(Location location, String 
container) {
+      BucketTemplate template = new BucketTemplate().name(container);
+      if (location != null) {
+         
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location 
gcsLocation = 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location
+                  .fromValue(location.getId());
+         template = template.location(gcsLocation);
+      }
+      return api.getBucketApi().createBucket(projectId.get(), template) != 
null;
+   }
+
+   @Override
+   public boolean createContainerInLocation(Location location, String 
container, CreateContainerOptions options) {
+      BucketTemplate template = new BucketTemplate().name(container);
+      if (location != null) {
+         
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location 
gcsLocation = 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location
+                  .fromValue(location.getId());
+         template = template.location(gcsLocation);
+      }
+      Bucket bucket = api.getBucketApi().createBucket(projectId.get(), 
template);
+      if (options.isPublicRead()) {
+         try {
+            DefaultObjectAccessControlsTemplate doAclTemplate = new 
DefaultObjectAccessControlsTemplate().entity(
+                     "allUsers").role(ObjectRole.READER);
+            
api.getDefaultObjectAccessControlsApi().createDefaultObjectAccessControls(container,
 doAclTemplate);
+         } catch (HttpResponseException e) {
+            // If DefaultObjectAccessControls operation fail, Reverse create 
operation the operation.
+            api.getBucketApi().deleteBucket(container);
+            return false;
+         }
+      }
+
+      return bucket != null;
+   }
+
+   /** Returns list of of all the objects */
+   @Override
+   public PageSet<? extends StorageMetadata> list(String container) {
+      ListPage<GCSObject> gcsList = api.getObjectApi().listObjects(container);
+      PageSet<? extends StorageMetadata> list = 
objectListToStorageMetadata.apply(gcsList);
+      return list;
+   }
+
+   @Override
+   public PageSet<? extends StorageMetadata> list(String container, 
ListContainerOptions options) {
+
+      if (options != null && options != ListContainerOptions.NONE) {
+         ListObjectOptions listOptions = 
listContainerOptionsToListObjectOptions.apply(options);
+         ListPage<GCSObject> gcsList = 
api.getObjectApi().listObjects(container, listOptions);
+         PageSet<? extends StorageMetadata> list = 
objectListToStorageMetadata.apply(gcsList);
+         return options.isDetailed() ? 
fetchBlobMetadataProvider.get().setContainerName(container).apply(list) : list;
+      } else {
+         return list(container);
+      }
+   }
+
+   /**
+    * Checks whether an accessible object is available. Google cloud storage 
does not support directly support
+    * BucketExist or ObjectExist operations
+    */
+   @Override
+   public boolean blobExists(String container, String name) {
+      try {
+         String urlName = name.contains("/") ? URLEncoder.encode(name, 
Charsets.UTF_8.toString()) : name;
+         return api.getObjectApi().objectExist(container, urlName);
+      } catch (UnsupportedEncodingException e) {
+         throw Throwables.propagate(e);
+      }
+   }
+
+   /**
+    * This supports multipart/related upload which has exactly 2 parts, 
media-part and metadata-part
+    */
+   @Override
+   public String putBlob(String container, Blob blob) {
+      checkNotNull(blob.getPayload().getContentMetadata().getContentLength());
+      HashCode md5 = 
blob.getMetadata().getContentMetadata().getContentMD5AsHashCode();
+
+      ObjectTemplate template = 
blobMetadataToObjectTemplate.apply(blob.getMetadata());
+
+      if (md5 != null) {
+         template.md5Hash(md5);
+      }
+      return api.getObjectApi().multipartUpload(container, template, 
blob.getPayload()).getEtag();
+   }
+
+   @Override
+   public String putBlob(String container, Blob blob, PutOptions options) {
+      if (options.multipart().isMultipart()) {
+         return multipartUploadStrategy.execute(container, blob);
+      } else {
+         return putBlob(container, blob);
+      }
+   }
+
+   @Override
+   public BlobMetadata blobMetadata(String container, String name) {
+      return 
objectToBlobMetadata.apply(api.getObjectApi().getObject(container, name));
+   }
+
+   @Override
+   public Blob getBlob(String container, String name, 
org.jclouds.blobstore.options.GetOptions options) {
+      PayloadEnclosingImpl impl = api.getObjectApi().download(container, name);
+
+      GCSObject gcsObject = api.getObjectApi().getObject(container, name);
+      if (gcsObject == null) {
+         return null;
+      }
+      Blob blob = new 
BlobBuilderImpl().payload(impl.getPayload()).payload(impl.getPayload())
+               
.contentType(gcsObject.getContentType()).contentDisposition(gcsObject.getContentDisposition())
+               
.contentEncoding(gcsObject.getContentEncoding()).contentLanguage(gcsObject.getContentLanguage())
+               
.contentLength(gcsObject.getSize()).contentMD5(gcsObject.getMd5HashCode()).name(gcsObject.getName())
+               .userMetadata(gcsObject.getAllMetadata()).build();
+      blob.getMetadata().setContainer(container);
+      blob.getMetadata().setLastModified(gcsObject.getUpdated());
+      blob.getMetadata().setETag(gcsObject.getEtag());
+      blob.getMetadata().setPublicUri(gcsObject.getMediaLink());
+      blob.getMetadata().setUserMetadata(gcsObject.getAllMetadata());
+      blob.getMetadata().setUri(gcsObject.getSelfLink());
+      blob.getMetadata().setId(gcsObject.getId());
+      return blob;
+   }
+
+   @Override
+   public void removeBlob(String container, String name) {
+      String urlName;
+      try {
+         urlName = name.contains("/") ? URLEncoder.encode(name, 
Charsets.UTF_8.toString()) : name;
+      } catch (UnsupportedEncodingException uee) {
+         throw Throwables.propagate(uee);
+      }
+      api.getObjectApi().deleteObject(container, urlName);
+   }
+
+   @Override
+   protected boolean deleteAndVerifyContainerGone(String container) {
+      ListPage<GCSObject> list = api.getObjectApi().listObjects(container);
+      if (list == null) {
+         return api.getBucketApi().deleteBucket(container);
+      }
+      if (!list.iterator().hasNext() && list.getPrefixes().isEmpty())
+         return api.getBucketApi().deleteBucket(container);
+
+      return false;
+   }
+
+   public Set<String> listPrefixes(String container, ListContainerOptions 
options) {
+      ListObjectOptions gcsOptions = 
listContainerOptionsToListObjectOptions.apply(options);
+      Set<String> prefixes = api.getObjectApi().listObjects(container, 
gcsOptions).getPrefixes();
+      return prefixes;
+   }
+
+   public Set<String> listPrefixes(String container) {
+      return listPrefixes(container, ListContainerOptions.NONE);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/config/GCSBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/config/GCSBlobStoreContextModule.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/config/GCSBlobStoreContextModule.java
new file mode 100644
index 0000000..f10cadc
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/config/GCSBlobStoreContextModule.java
@@ -0,0 +1,35 @@
+/*
+ * 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.googlecloudstorage.blobstore.config;
+
+import org.jclouds.blobstore.AsyncBlobStore;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.attr.ConsistencyModel;
+import org.jclouds.googlecloudstorage.blobstore.GCSAsyncBlobStore;
+import org.jclouds.googlecloudstorage.blobstore.GCSBlobStore;
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+
+public class GCSBlobStoreContextModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
+      bind(BlobStore.class).to(GCSBlobStore.class).in(Scopes.SINGLETON);
+      
bind(AsyncBlobStore.class).to(GCSAsyncBlobStore.class).in(Scopes.SINGLETON);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobMetadataToObjectTemplate.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobMetadataToObjectTemplate.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobMetadataToObjectTemplate.java
new file mode 100644
index 0000000..d604f7c
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobMetadataToObjectTemplate.java
@@ -0,0 +1,57 @@
+/*
+ * 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.googlecloudstorage.blobstore.functions;
+
+import java.util.Map;
+
+import javax.inject.Singleton;
+
+import org.jclouds.blobstore.domain.BlobMetadata;
+import org.jclouds.googlecloudstorage.domain.templates.ObjectTemplate;
+import org.jclouds.io.ContentMetadata;
+
+import com.google.common.base.Function;
+import com.google.common.hash.HashCode;
+
+@Singleton
+public class BlobMetadataToObjectTemplate implements Function<BlobMetadata, 
ObjectTemplate> {
+
+   public ObjectTemplate apply(BlobMetadata from) {
+      if (from == null)
+         return null;
+
+      String name = from.getName();
+      Map<String, String> userMeta = from.getUserMetadata();
+
+      ContentMetadata metadata = from.getContentMetadata();
+      String contentDisposition = metadata.getContentDisposition();
+      String contentEncoding = metadata.getContentEncoding();
+      String contentLanguage = metadata.getContentLanguage();
+      String contentType = metadata.getContentType();
+      Long contentLength = metadata.getContentLength();
+
+      HashCode md5 = metadata.getContentMD5AsHashCode();
+
+      ObjectTemplate template = new 
ObjectTemplate().contentType(contentType).size(contentLength)
+               
.contentEncoding(contentEncoding).contentLanguage(contentLanguage)
+               
.contentDisposition(contentDisposition).name(name).customMetadata(userMeta);
+      if (md5 != null) {
+         template.md5Hash(md5);
+      }
+      return template;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobStoreListContainerOptionsToListObjectOptions.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobStoreListContainerOptionsToListObjectOptions.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobStoreListContainerOptionsToListObjectOptions.java
new file mode 100644
index 0000000..d4f8ef1
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BlobStoreListContainerOptionsToListObjectOptions.java
@@ -0,0 +1,50 @@
+/*
+ * 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.googlecloudstorage.blobstore.functions;
+
+import org.jclouds.blobstore.options.ListContainerOptions;
+import org.jclouds.googlecloudstorage.options.ListObjectOptions;
+
+import com.google.common.base.Function;
+import com.google.inject.Singleton;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class BlobStoreListContainerOptionsToListObjectOptions implements
+         Function<ListContainerOptions, ListObjectOptions> {
+   public ListObjectOptions apply(ListContainerOptions from) {
+      checkNotNull(from, "set options to instance NONE instead of passing 
null");
+      ListObjectOptions httpOptions = new ListObjectOptions();
+
+      if (!from.isRecursive()) {
+         httpOptions = httpOptions.delimiter("/");
+      }
+      if (from.getDir() != null) {
+         String path = from.getDir();
+         if (!path.endsWith("/"))
+            path += "/";
+         httpOptions = httpOptions.prefix(path);
+      }
+      if (from.getMarker() != null) {
+         httpOptions = httpOptions.pageToken(from.getMarker());
+      }
+      if (from.getMaxResults() != null) {
+         httpOptions = httpOptions.maxResults(from.getMaxResults());
+      }
+      return httpOptions;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BucketToStorageMetadata.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BucketToStorageMetadata.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BucketToStorageMetadata.java
new file mode 100644
index 0000000..e402c6b
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/BucketToStorageMetadata.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.googlecloudstorage.blobstore.functions;
+
+import org.jclouds.blobstore.domain.MutableStorageMetadata;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
+import org.jclouds.domain.Location;
+import org.jclouds.googlecloudstorage.domain.Bucket;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class BucketToStorageMetadata implements Function<Bucket, 
StorageMetadata> {
+   private Supplier<Location> defaultLocation;
+
+   @Inject
+   BucketToStorageMetadata(Supplier<Location> defaultLocation) {
+      this.defaultLocation = defaultLocation;
+   }
+
+   public StorageMetadata apply(Bucket from) {
+      MutableStorageMetadata to = new MutableStorageMetadataImpl();
+      to.setName(from.getName());
+      to.setLocation(defaultLocation.get());
+      to.setType(StorageType.CONTAINER);
+      return to;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectListToStorageMetadata.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectListToStorageMetadata.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectListToStorageMetadata.java
new file mode 100644
index 0000000..341e44e
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectListToStorageMetadata.java
@@ -0,0 +1,65 @@
+/*
+ * 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.googlecloudstorage.blobstore.functions;
+
+import java.util.Map;
+import org.jclouds.blobstore.domain.BlobMetadata;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.domain.internal.PageSetImpl;
+import org.jclouds.blobstore.domain.internal.StorageMetadataImpl;
+import org.jclouds.googlecloudstorage.domain.GCSObject;
+import org.jclouds.googlecloudstorage.domain.ListPage;
+import org.jclouds.googlecloudstorage.domain.Resource.Kind;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class ObjectListToStorageMetadata implements 
Function<ListPage<GCSObject>, PageSet<? extends StorageMetadata>> {
+   private final ObjectToBlobMetadata object2blobMd;
+
+   @Inject
+   public ObjectListToStorageMetadata(ObjectToBlobMetadata object2blobMd) {
+      this.object2blobMd = object2blobMd;
+   }
+
+   public PageSet<? extends StorageMetadata> apply(ListPage<GCSObject> from) {
+      if (from == null) {
+         from = ListPage.<GCSObject> builder().kind(Kind.OBJECTS).build();
+      }
+
+      return new 
PageSetImpl<StorageMetadata>(Iterables.transform(Iterables.transform(from, 
object2blobMd),
+               new Function<BlobMetadata, StorageMetadata>() {
+                  public StorageMetadata apply(BlobMetadata input) {
+                     Map<String, String> userMetaData = (input != null && 
input.getUserMetadata() != null) ? input
+                              .getUserMetadata() : ImmutableMap.<String, 
String> of();
+                     if 
(input.getContentMetadata().getContentType().equals("application/directory")) {
+                        return new 
StorageMetadataImpl(StorageType.RELATIVE_PATH, input.getProviderId(), input
+                                 .getName(), input.getLocation(), 
input.getUri(), input.getETag(), input
+                                 .getCreationDate(), input.getLastModified(), 
userMetaData);
+                     }
+                     return input;
+                  }
+               }), from.getNextPageToken());
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectToBlobMetadata.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectToBlobMetadata.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectToBlobMetadata.java
new file mode 100644
index 0000000..ced893a
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/functions/ObjectToBlobMetadata.java
@@ -0,0 +1,79 @@
+/*
+ * 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.googlecloudstorage.blobstore.functions;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.blobstore.domain.MutableBlobMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
+import org.jclouds.blobstore.strategy.IfDirectoryReturnNameStrategy;
+import org.jclouds.googlecloudstorage.domain.GCSObject;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+
+@Singleton
+public class ObjectToBlobMetadata implements Function<GCSObject, 
MutableBlobMetadata> {
+   private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
+
+   @Inject
+   public ObjectToBlobMetadata(IfDirectoryReturnNameStrategy 
ifDirectoryReturnName) {
+      this.ifDirectoryReturnName = ifDirectoryReturnName;
+   }
+
+   public MutableBlobMetadata apply(GCSObject from) {
+      if (from == null)
+         return null;
+      MutableBlobMetadata to = new MutableBlobMetadataImpl();
+
+      if (from.getMd5HashCode() != null)
+         to.getContentMetadata().setContentMD5(from.getMd5HashCode());
+      if (from.getContentType() != null)
+         to.getContentMetadata().setContentType(from.getContentType());
+      if (from.getContentDisposition() != null)
+         
to.getContentMetadata().setContentDisposition(from.getContentDisposition());
+      if (from.getContentEncoding() != null)
+         to.getContentMetadata().setContentEncoding(from.getContentEncoding());
+      if (from.getContentLanguage() != null)
+         to.getContentMetadata().setContentLanguage(from.getContentLanguage());
+      if (from.getSize() != null)
+         to.getContentMetadata().setContentLength(from.getSize());
+      if (from.getUpdated() != null)
+         to.setLastModified(from.getUpdated());
+      to.setContainer(from.getBucket());
+      Map<String, String> userMeta = from.getAllMetadata() == null ? 
ImmutableMap.<String, String> of() : from
+               .getAllMetadata();
+      to.setUserMetadata(userMeta);
+      to.setETag(from.getEtag());
+      to.setName(from.getName());
+      to.setUri(from.getSelfLink());
+      to.setId(from.getId());
+      to.setPublicUri(from.getMediaLink());
+
+      String directoryName = ifDirectoryReturnName.execute(to);
+      if (directoryName != null) {
+         to.setName(directoryName);
+         to.setType(StorageType.RELATIVE_PATH);
+      } else {
+         to.setType(StorageType.BLOB);
+      }
+      return to;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartNamingStrategy.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartNamingStrategy.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartNamingStrategy.java
new file mode 100644
index 0000000..89e76a3
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartNamingStrategy.java
@@ -0,0 +1,30 @@
+/*
+ * 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.googlecloudstorage.blobstore.strategy.internal;
+
+import javax.inject.Singleton;
+
+@Singleton
+public class MultipartNamingStrategy {
+
+   private static final String PART_SEPARATOR = "_";
+
+   protected String getPartName(String key, int partNumber, int totalParts) {
+      int base = (int) Math.log10(totalParts) + 1;
+      return String.format("%s%s%0" + base + "d", key, PART_SEPARATOR, 
partNumber);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUpload.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUpload.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUpload.java
new file mode 100644
index 0000000..2edc6c5
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUpload.java
@@ -0,0 +1,36 @@
+/*
+ * 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.googlecloudstorage.blobstore.strategy.internal;
+
+public final class MultipartUpload {
+
+   private MultipartUpload() {
+   }
+
+   /* Maximum number of parts per upload */
+   public static final int MAX_NUMBER_OF_PARTS = 10000;
+   /* Maximum number of parts returned for a list parts request */
+   public static final int MAX_LIST_PARTS_RETURNED = 1000;
+   /* Maximum number of multipart uploads returned in a list multipart uploads 
request */
+   public static final int MAX_LIST_MPU_RETURNED = 1000;
+
+   /**
+    * part size 5 MB to 5 GB, last part can be < 5 MB
+    */
+   public static final long MIN_PART_SIZE = 5L * 1024L * 1024L;
+   public static final long MAX_PART_SIZE = 5L * 1024L * 1024L * 1024L;
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java
new file mode 100644
index 0000000..44c0b8b
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java
@@ -0,0 +1,138 @@
+/*
+ * 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.googlecloudstorage.blobstore.strategy.internal;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.Inject;
+import org.jclouds.blobstore.reference.BlobStoreConstants;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+public class MultipartUploadSlicingAlgorithm {
+
+   @Resource
+   @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   @VisibleForTesting
+   static final long DEFAULT_PART_SIZE = 32 * 1024 * 1024;
+
+   @VisibleForTesting
+   static final int DEFAULT_MAGNITUDE_BASE = 100;
+
+   @Inject(optional = true)
+   @Named("jclouds.mpu.parts.size")
+   @VisibleForTesting
+   long defaultPartSize = DEFAULT_PART_SIZE;
+
+   @Inject(optional = true)
+   @Named("jclouds.mpu.parts.magnitude")
+   @VisibleForTesting
+   int magnitudeBase = DEFAULT_MAGNITUDE_BASE;
+
+   // calculated only once, but not from the constructor
+   private volatile int parts; // required number of parts with chunkSize
+   private volatile long chunkSize;
+   private volatile long remaining; // number of bytes remained for the last 
part
+
+   // sequentially updated values
+   private volatile int part;
+   private volatile long chunkOffset;
+   private volatile long copied;
+
+   @VisibleForTesting
+   protected long calculateChunkSize(long length) {
+      long unitPartSize = defaultPartSize; // first try with default part size
+      int parts = (int) (length / unitPartSize);
+      long partSize = unitPartSize;
+      int magnitude = parts / magnitudeBase;
+      if (magnitude > 0) {
+         partSize = magnitude * unitPartSize;
+         if (partSize > MultipartUpload.MAX_PART_SIZE) {
+            partSize = MultipartUpload.MAX_PART_SIZE;
+            unitPartSize = MultipartUpload.MAX_PART_SIZE;
+         }
+         parts = (int) (length / partSize);
+         if (parts * partSize < length) {
+            partSize = (magnitude + 1) * unitPartSize;
+            if (partSize > MultipartUpload.MAX_PART_SIZE) {
+               partSize = MultipartUpload.MAX_PART_SIZE;
+               unitPartSize = MultipartUpload.MAX_PART_SIZE;
+            }
+            parts = (int) (length / partSize);
+         }
+      }
+      if (parts > MultipartUpload.MAX_NUMBER_OF_PARTS) { // if splits in too 
many parts or
+         // cannot be split
+         unitPartSize = MultipartUpload.MIN_PART_SIZE; // take the minimum 
part size
+         parts = (int) (length / unitPartSize);
+      }
+      if (parts > MultipartUpload.MAX_NUMBER_OF_PARTS) { // if still splits in 
too many parts
+         parts = MultipartUpload.MAX_NUMBER_OF_PARTS - 1; // limit them. do 
not care about not
+         // covering
+      }
+      long remainder = length % unitPartSize;
+      if (remainder == 0 && parts > 0) {
+         parts -= 1;
+      }
+      this.chunkSize = partSize;
+      this.parts = parts;
+      this.remaining = length - partSize * parts;
+      logger.debug(" %d bytes partitioned in %d parts of part size: %d, 
remaining: %d%s", length, parts, chunkSize,
+               remaining, remaining > MultipartUpload.MAX_PART_SIZE ? " 
overflow!" : "");
+      return this.chunkSize;
+   }
+
+   public long getCopied() {
+      return copied;
+   }
+
+   public void setCopied(long copied) {
+      this.copied = copied;
+   }
+
+   @VisibleForTesting
+   protected int getParts() {
+      return parts;
+   }
+
+   protected int getNextPart() {
+      return ++part;
+   }
+
+   protected void addCopied(long copied) {
+      this.copied += copied;
+   }
+
+   protected long getNextChunkOffset() {
+      long next = chunkOffset;
+      chunkOffset += getChunkSize();
+      return next;
+   }
+
+   @VisibleForTesting
+   protected long getChunkSize() {
+      return chunkSize;
+   }
+
+   @VisibleForTesting
+   protected long getRemaining() {
+      return remaining;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadStrategy.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadStrategy.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadStrategy.java
new file mode 100644
index 0000000..89c4879
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/MultipartUploadStrategy.java
@@ -0,0 +1,26 @@
+/*
+ * 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.googlecloudstorage.blobstore.strategy.internal;
+
+import org.jclouds.blobstore.domain.Blob;
+
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(SequentialMultipartUploadStrategy.class)
+public abstract class MultipartUploadStrategy {
+   public abstract String execute(String container, Blob blob);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
new file mode 100644
index 0000000..d6522b5
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/strategy/internal/SequentialMultipartUploadStrategy.java
@@ -0,0 +1,106 @@
+/*
+ * 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.googlecloudstorage.blobstore.strategy.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.BlobBuilder;
+import org.jclouds.blobstore.reference.BlobStoreConstants;
+import org.jclouds.googlecloudstorage.GoogleCloudStorageApi;
+import 
org.jclouds.googlecloudstorage.blobstore.functions.BlobMetadataToObjectTemplate;
+import org.jclouds.googlecloudstorage.domain.GCSObject;
+import org.jclouds.googlecloudstorage.domain.templates.ComposeObjectTemplate;
+import org.jclouds.googlecloudstorage.domain.templates.ObjectTemplate;
+import org.jclouds.io.Payload;
+import org.jclouds.io.PayloadSlicer;
+import org.jclouds.logging.Logger;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+
+public class SequentialMultipartUploadStrategy extends MultipartUploadStrategy 
{
+
+   @Resource
+   @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
+   private Logger logger = Logger.NULL;
+
+   private final GoogleCloudStorageApi api;
+   private final Provider<BlobBuilder> blobBuilders;
+   private final BlobMetadataToObjectTemplate blob2ObjectTemplate;
+   private final MultipartUploadSlicingAlgorithm algorithm;
+   private final PayloadSlicer slicer;
+   private final MultipartNamingStrategy namingStrategy;
+
+   @Inject
+   public SequentialMultipartUploadStrategy(GoogleCloudStorageApi api, 
Provider<BlobBuilder> blobBuilders,
+            BlobMetadataToObjectTemplate blob2ObjectTemplate, 
MultipartUploadSlicingAlgorithm algorithm,
+            PayloadSlicer slicer, MultipartNamingStrategy namingStrategy) {
+      this.api = checkNotNull(api, "api");
+      this.blobBuilders = checkNotNull(blobBuilders, "blobBuilders");
+      this.blob2ObjectTemplate = checkNotNull(blob2ObjectTemplate, 
"blob2Object");
+      this.algorithm = checkNotNull(algorithm, "algorithm");
+      this.slicer = checkNotNull(slicer, "slicer");
+      this.namingStrategy = checkNotNull(namingStrategy, "namingStrategy");
+   }
+
+   @Override
+   public String execute(String container, Blob blob) {
+
+      ObjectTemplate destination = 
blob2ObjectTemplate.apply(blob.getMetadata());
+      ComposeObjectTemplate template = new 
ComposeObjectTemplate().destination(destination);
+
+      Set<GCSObject> sourceList = Sets.newHashSet();
+
+      String key = blob.getMetadata().getName();
+      Payload payload = blob.getPayload();
+      Long length = payload.getContentMetadata().getContentLength();
+      if (length == null) {
+         length = blob.getMetadata().getContentMetadata().getContentLength();
+         payload.getContentMetadata().setContentLength(length);
+      }
+      checkNotNull(length,
+               "please invoke 
payload.getContentMetadata().setContentLength(length) prior to multipart 
upload");
+      long chunkSize = algorithm.calculateChunkSize(length);
+      int partCount = algorithm.getParts();
+      if (partCount > 0) {
+         for (Payload part : slicer.slice(payload, chunkSize)) {
+            int partNum = algorithm.getNextPart();
+            String partName = namingStrategy.getPartName(key, partNum, 
partCount);
+            long partSize = ((partCount + 1) == partNum) ? 
algorithm.getRemaining() : algorithm.getChunkSize();
+            Blob blobPart = 
blobBuilders.get().name(partName).payload(part).contentDisposition(partName)
+                     
.contentLength(partSize).contentType(blob.getMetadata().getContentMetadata().getContentType())
+                     .build();
+            GCSObject object = api.getObjectApi().multipartUpload(container,
+                     blob2ObjectTemplate.apply(blobPart.getMetadata()), 
blobPart.getPayload());
+            sourceList.add(object);
+         }
+         template = template.sourceObjects(sourceList);
+         return api.getObjectApi().composeObjects(container, key, 
template).getEtag();
+      } else {
+         return api.getObjectApi()
+                  .multipartUpload(container, 
blob2ObjectTemplate.apply(blob.getMetadata()), blob.getPayload())
+                  .getEtag();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/GoogleCloudStorageHttpApiModule.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/GoogleCloudStorageHttpApiModule.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/GoogleCloudStorageHttpApiModule.java
index a8c0bdb..56f6ac6 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/GoogleCloudStorageHttpApiModule.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/GoogleCloudStorageHttpApiModule.java
@@ -16,14 +16,33 @@
  */
 package org.jclouds.googlecloudstorage.config;
 
+import static com.google.common.base.Suppliers.compose;
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.Credentials;
 import org.jclouds.googlecloudstorage.GoogleCloudStorageApi;
 import org.jclouds.googlecloudstorage.handlers.GoogleCloudStorageErrorHandler;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
 import org.jclouds.http.annotation.ServerError;
+import org.jclouds.location.Provider;
+import org.jclouds.rest.AuthorizationException;
 import org.jclouds.rest.ConfiguresHttpApi;
 import org.jclouds.rest.config.HttpApiModule;
+import 
org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.inject.Provides;
 
 /**
  * Configures the GoogleCloud connection.
@@ -40,4 +59,26 @@ public class GoogleCloudStorageHttpApiModule extends 
HttpApiModule<GoogleCloudSt
       
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GoogleCloudStorageErrorHandler.class);
    }
 
+   @Provides
+   @Singleton
+   @UserProject
+   public Supplier<String> supplyProject(@Provider final Supplier<Credentials> 
creds, final GoogleCloudStorageApi api,
+            AtomicReference<AuthorizationException> authException, 
@Named(PROPERTY_SESSION_INTERVAL) long seconds) {
+      return 
MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
+               compose(new Function<Credentials, String>() {
+                  public String apply(Credentials in) {
+                     // ID should be of the form 
[email protected]
+                     // OR (increasingly often) 
[email protected]
+                     String projectName = in.identity;
+                     if (projectName.indexOf("@") != -1) {
+                        projectName = 
Iterables.get(Splitter.on("@").split(projectName), 0);
+                        if (projectName.indexOf("-") != -1) {
+                           // if ID is of the form 
[email protected]
+                           projectName = 
Iterables.get(Splitter.on("-").split(projectName), 0);
+                        }
+                     }
+                     return projectName;
+                  }
+               }, creds), seconds, TimeUnit.SECONDS);
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/UserProject.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/UserProject.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/UserProject.java
new file mode 100644
index 0000000..ae59af0
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/config/UserProject.java
@@ -0,0 +1,33 @@
+/*
+ * 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.googlecloudstorage.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;
+
+/**
+ * Qualifies a property as the user's project id.
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, 
ElementType.METHOD})
+@Qualifier
+public @interface UserProject {
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/Bucket.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/Bucket.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/Bucket.java
index 2f47f7f..d80a99e 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/Bucket.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/Bucket.java
@@ -24,8 +24,8 @@ import java.net.URI;
 import java.util.Date;
 import java.util.Set;
 
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.Location;
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.StorageClass;
+import org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.StorageClass;
 import org.jclouds.googlecloudstorage.domain.internal.BucketCors;
 import org.jclouds.googlecloudstorage.domain.internal.BucketLifeCycle;
 import org.jclouds.googlecloudstorage.domain.internal.Logging;

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/BucketAccessControls.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/BucketAccessControls.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/BucketAccessControls.java
index 3bf4f28..6d0d0ed 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/BucketAccessControls.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/BucketAccessControls.java
@@ -21,7 +21,7 @@ import static 
com.google.common.base.Preconditions.checkNotNull;
 
 import java.net.URI;
 
-import org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.Role;
+import org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Role;
 import org.jclouds.googlecloudstorage.domain.internal.ProjectTeam;
 import org.jclouds.javax.annotation.Nullable;
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DefaultObjectAccessControls.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DefaultObjectAccessControls.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DefaultObjectAccessControls.java
index 7509735..aeddc41 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DefaultObjectAccessControls.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DefaultObjectAccessControls.java
@@ -21,7 +21,7 @@ import static 
com.google.common.base.Preconditions.checkNotNull;
 
 import java.net.URI;
 
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.ObjectRole;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.ObjectRole;
 import org.jclouds.googlecloudstorage.domain.internal.ProjectTeam;
 import org.jclouds.javax.annotation.Nullable;
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceReferences.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceReferences.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceReferences.java
new file mode 100644
index 0000000..272074b
--- /dev/null
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceReferences.java
@@ -0,0 +1,105 @@
+/*
+ * 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.googlecloudstorage.domain;
+
+import com.google.common.base.CaseFormat;
+
+public final class DomainResourceReferences {
+
+   private DomainResourceReferences() {
+   }
+
+   public enum Role {
+      READER, WRITER, OWNER
+   }
+
+   public enum ObjectRole {
+      READER, OWNER
+   }
+
+   public enum Location {
+      ASIA, EU, US, ASIA_EAST1, US_CENTRAL1, US_CENTRAL2, US_EAST1, US_EAST2, 
US_EAST3, US_WEST1;
+
+      public String value() {
+         return name().replace('_', '-');
+      }
+
+      @Override
+      public String toString() {
+         return value();
+      }
+
+      public static Location fromValue(String location) {
+         return valueOf(location.replace('-', '_'));
+      }
+   }
+
+   public enum StorageClass {
+      STANDARD, DURABLE_REDUCED_AVAILABILITY;
+   }
+
+   public enum Projection {
+      NO_ACL, FULL;
+
+      public String value() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
+      }
+
+      @Override
+      public String toString() {
+         return value();
+      }
+
+      public static Projection fromValue(String projection) {
+         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
projection));
+      }
+   }
+
+   public enum PredefinedAcl {
+      AUTHENTICATED_READ, PRIVATE, PROJEECT_PRIVATE, PUBLIC_READ, 
PUBLIC_READ_WRITE;
+
+      public String value() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
+      }
+
+      @Override
+      public String toString() {
+         return value();
+      }
+
+      public static PredefinedAcl fromValue(String predefinedAcl) {
+         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
predefinedAcl));
+      }
+   }
+
+   public enum DestinationPredefinedAcl {
+      AUTHENTICATED_READ, BUCKET_OWNER_FULLCONTROL, BUCKET_OWNER_READ, 
PRIVATE, PROJECT_PRIVATE, PUBLIC_READ;
+
+      public String value() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
+      }
+
+      @Override
+      public String toString() {
+         return value();
+      }
+
+      public static DestinationPredefinedAcl fromValue(String 
destinationPredefinedAcl) {
+         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
destinationPredefinedAcl));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceRefferences.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceRefferences.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceRefferences.java
deleted file mode 100644
index 82b3442..0000000
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/DomainResourceRefferences.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecloudstorage.domain;
-
-import com.google.common.base.CaseFormat;
-
-public final class DomainResourceRefferences {
-
-   private DomainResourceRefferences() {
-   }
-
-   public enum Role {
-      READER, WRITER, OWNER
-   }
-
-   public enum ObjectRole {
-      READER, OWNER
-   }
-
-   public enum Location {
-      ASIA, EU, US, ASIA_EAST1, US_CENTRAL1, US_CENTRAL2, US_EAST1, US_EAST2, 
US_EAST3, US_WEST1;
-
-      public String value() {
-         return name().replace('_', '-');       
-      }
-
-      @Override
-      public String toString() {
-         return value();
-      }
-
-      public static Location fromValue(String location) {
-         return valueOf(location.replace('-', '_'));      
-      }
-   }
-
-   public enum StorageClass {
-      STANDARD, DURABLE_REDUCED_AVAILABILITY;
-   }
-
-   public enum Projection {
-      NO_ACL, FULL;
-
-      public String value() {
-         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
-      }
-
-      @Override
-      public String toString() {
-         return value();
-      }
-
-      public static Projection fromValue(String projection) {
-         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
projection));
-      }
-   }
-
-   public enum PredefinedAcl {
-      AUTHENTICATED_READ, PRIVATE, PROJEECT_PRIVATE, PUBLIC_READ, 
PUBLIC_READ_WRITE;
-
-      public String value() {
-         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
-      }
-
-      @Override
-      public String toString() {
-         return value();
-      }
-
-      public static PredefinedAcl fromValue(String predefinedAcl) {
-         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
predefinedAcl));
-      }
-   }
-
-   public enum DestinationPredefinedAcl {
-      AUTHENTICATED_READ, BUCKET_OWNER_FULLCONTROL, BUCKET_OWNER_READ, 
PRIVATE, PROJECT_PRIVATE, PUBLIC_READ;
-
-      public String value() {
-         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name());
-      }
-
-      @Override
-      public String toString() {
-         return value();
-      }
-
-      public static DestinationPredefinedAcl fromValue(String 
destinationPredefinedAcl) {
-         return valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, 
destinationPredefinedAcl));
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/GCSObject.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/GCSObject.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/GCSObject.java
index fdce717..50c1bca 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/GCSObject.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/GCSObject.java
@@ -24,7 +24,7 @@ import java.util.Date;
 import java.util.Map;
 import java.util.Set;
 
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.StorageClass;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.StorageClass;
 import org.jclouds.googlecloudstorage.domain.internal.Owner;
 
 import com.google.common.base.Objects;
@@ -132,8 +132,11 @@ public class GCSObject extends Resource {
    }
 
    public HashCode getMd5HashCode() {
-      HashCode hc = HashCode.fromBytes(BaseEncoding.base64().decode(md5Hash));
-      return hc;
+      if (md5Hash != null) {
+         HashCode hc = 
HashCode.fromBytes(BaseEncoding.base64().decode(md5Hash));
+         return hc;
+      }
+      return null;
    }
 
    public URI getMediaLink() {
@@ -173,8 +176,12 @@ public class GCSObject extends Resource {
    }
 
    public HashCode getCrc32cHashcode() {
-      HashCode hc = 
HashCode.fromBytes(DomainUtils.reverse(BaseEncoding.base64().decode(crc32c)));
-      return hc;
+      if (crc32c != null) {
+         HashCode hc = 
HashCode.fromBytes(DomainUtils.reverse(BaseEncoding.base64().decode(crc32c)));
+         return hc;
+      }
+      return null;
+
    }
 
    public Integer getComponentCount() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/ObjectAccessControls.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/ObjectAccessControls.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/ObjectAccessControls.java
index 00e29c4..3cf559f 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/ObjectAccessControls.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/ObjectAccessControls.java
@@ -21,7 +21,7 @@ import static 
com.google.common.base.Preconditions.checkNotNull;
 
 import java.net.URI;
 
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.ObjectRole;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.ObjectRole;
 import org.jclouds.googlecloudstorage.domain.internal.ProjectTeam;
 import org.jclouds.javax.annotation.Nullable;
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/ccc2d243/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/templates/BucketTemplate.java
----------------------------------------------------------------------
diff --git 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/templates/BucketTemplate.java
 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/templates/BucketTemplate.java
index b2ea6da..6858166 100644
--- 
a/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/templates/BucketTemplate.java
+++ 
b/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/domain/templates/BucketTemplate.java
@@ -21,8 +21,8 @@ import java.util.Set;
 
 import org.jclouds.googlecloudstorage.domain.BucketAccessControls;
 import org.jclouds.googlecloudstorage.domain.DefaultObjectAccessControls;
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.Location;
-import 
org.jclouds.googlecloudstorage.domain.DomainResourceRefferences.StorageClass;
+import org.jclouds.googlecloudstorage.domain.DomainResourceReferences.Location;
+import 
org.jclouds.googlecloudstorage.domain.DomainResourceReferences.StorageClass;
 import org.jclouds.googlecloudstorage.domain.internal.BucketCors;
 import org.jclouds.googlecloudstorage.domain.internal.BucketLifeCycle;
 import org.jclouds.googlecloudstorage.domain.internal.Logging;

Reply via email to