You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/10/05 17:50:06 UTC

[1/2] git commit: JCLOUDS-40 remove all implementations of AsyncBlobStore except Submission in preparation for complete removal.

Repository: jclouds
Updated Branches:
  refs/heads/master 8c520d39a -> 56a2a8bf4


JCLOUDS-40 remove all implementations of AsyncBlobStore except Submission in preparation for complete removal.


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

Branch: refs/heads/master
Commit: dfb583b67aba421f9aa48e97ebfbc5303420d3b7
Parents: 8c520d3
Author: Adrian Cole <ac...@twitter.com>
Authored: Sat Oct 4 22:35:32 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 5 08:49:38 2014 -0700

----------------------------------------------------------------------
 .../config/AtmosBlobStoreContextModule.java     |   3 -
 .../FilesystemBlobStoreContextModule.java       |   8 -
 .../config/S3BlobStoreContextModule.java        |   3 -
 .../config/SwiftBlobStoreContextModule.java     |   3 -
 .../org/jclouds/blobstore/AsyncBlobStore.java   |   3 +
 .../jclouds/blobstore/LocalAsyncBlobStore.java  | 558 ------------------
 .../blobstore/config/LocalBlobStore.java        | 562 ++++++++++++++++++-
 .../config/TransientBlobStoreContextModule.java |  10 -
 .../blobstore/internal/BaseAsyncBlobStore.java  | 310 ----------
 .../TransientBlobRequestSignerTest.java         |   3 +-
 .../config/AzureBlobStoreContextModule.java     |   3 -
 ...loudObjectStorageBlobStoreContextModule.java |   4 -
 12 files changed, 566 insertions(+), 904 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/config/AtmosBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/config/AtmosBlobStoreContextModule.java b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/config/AtmosBlobStoreContextModule.java
index a562ed6..c83dbf3 100644
--- a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/config/AtmosBlobStoreContextModule.java
+++ b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/config/AtmosBlobStoreContextModule.java
@@ -23,11 +23,9 @@ import javax.inject.Singleton;
 import org.jclouds.atmos.AtmosClient;
 import org.jclouds.atmos.blobstore.AtmosBlobRequestSigner;
 import org.jclouds.atmos.blobstore.AtmosBlobStore;
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.blobstore.internal.SubmissionAsyncBlobStore;
 
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
@@ -41,7 +39,6 @@ public class AtmosBlobStoreContextModule extends AbstractModule {
    @Override
    protected void configure() {
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
-      bind(AsyncBlobStore.class).to(SubmissionAsyncBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobStore.class).to(AtmosBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobRequestSigner.class).to(AtmosBlobRequestSigner.class);
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/apis/filesystem/src/main/java/org/jclouds/filesystem/config/FilesystemBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/apis/filesystem/src/main/java/org/jclouds/filesystem/config/FilesystemBlobStoreContextModule.java b/apis/filesystem/src/main/java/org/jclouds/filesystem/config/FilesystemBlobStoreContextModule.java
index 972abe9..9294450 100644
--- a/apis/filesystem/src/main/java/org/jclouds/filesystem/config/FilesystemBlobStoreContextModule.java
+++ b/apis/filesystem/src/main/java/org/jclouds/filesystem/config/FilesystemBlobStoreContextModule.java
@@ -16,12 +16,8 @@
  */
 package org.jclouds.filesystem.config;
 
-import static org.jclouds.rest.config.BinderUtils.bindSyncToAsyncApi;
-
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
-import org.jclouds.blobstore.LocalAsyncBlobStore;
 import org.jclouds.blobstore.LocalBlobRequestSigner;
 import org.jclouds.blobstore.LocalStorageStrategy;
 import org.jclouds.blobstore.attr.ConsistencyModel;
@@ -41,11 +37,7 @@ public class FilesystemBlobStoreContextModule extends AbstractModule {
 
    @Override
    protected void configure() {
-      bind(AsyncBlobStore.class).to(LocalAsyncBlobStore.class).asEagerSingleton();
-      // forward all requests from TransientBlobStore to TransientAsyncBlobStore.  needs above binding as cannot proxy a class
-      bindSyncToAsyncApi(binder(), LocalBlobStore.class, AsyncBlobStore.class);
       bind(BlobStore.class).to(LocalBlobStore.class);
-
       install(new BlobStoreObjectModule());
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
       bind(LocalStorageStrategy.class).to(FilesystemStorageStrategyImpl.class);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java
index 525f9bd..f820308 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/config/S3BlobStoreContextModule.java
@@ -22,11 +22,9 @@ import java.util.concurrent.TimeUnit;
 
 import javax.inject.Singleton;
 
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.blobstore.internal.SubmissionAsyncBlobStore;
 import org.jclouds.domain.Location;
 import org.jclouds.s3.S3Client;
 import org.jclouds.s3.blobstore.S3BlobRequestSigner;
@@ -47,7 +45,6 @@ public class S3BlobStoreContextModule extends AbstractModule {
    @Override
    protected void configure() {
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
-      bind(AsyncBlobStore.class).to(SubmissionAsyncBlobStore.class).in(SINGLETON);
       bind(BlobStore.class).to(S3BlobStore.class).in(SINGLETON);
       bind(new TypeLiteral<Function<String, Location>>() {
       }).to(LocationFromBucketName.class);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
index 5387b8a..2ecdc88 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
@@ -16,10 +16,8 @@
  */
 package org.jclouds.openstack.swift.blobstore.config;
 
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.blobstore.internal.SubmissionAsyncBlobStore;
 import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
 
 import com.google.inject.AbstractModule;
@@ -30,7 +28,6 @@ public class SwiftBlobStoreContextModule extends AbstractModule {
    @Override
    protected void configure() {
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
-      bind(AsyncBlobStore.class).to(SubmissionAsyncBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobStore.class).to(SwiftBlobStore.class).in(Scopes.SINGLETON);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java
index 22feebd..a121455 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java
@@ -23,6 +23,7 @@ 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.internal.SubmissionAsyncBlobStore;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.GetOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -31,6 +32,7 @@ import org.jclouds.domain.Location;
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.inject.ImplementedBy;
 
 /**
  * Provides hooks needed to run a blob store asynchronously
@@ -40,6 +42,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  *             supported. Please use {@link org.jclouds.blobstore.BlobStore}
  */
 @Deprecated
+@ImplementedBy(SubmissionAsyncBlobStore.class)
 public interface AsyncBlobStore {
    /**
     * @see BlobStore#getContext

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java
deleted file mode 100644
index 42e4124..0000000
--- a/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java
+++ /dev/null
@@ -1,558 +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.blobstore;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Throwables.getCausalChain;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.find;
-import static com.google.common.collect.Iterables.size;
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Sets.filter;
-import static com.google.common.collect.Sets.newTreeSet;
-import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
-import static com.google.common.util.concurrent.Futures.immediateFuture;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.Date;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.regex.Pattern;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.Constants;
-import org.jclouds.blobstore.domain.Blob;
-import org.jclouds.blobstore.domain.Blob.Factory;
-import org.jclouds.blobstore.domain.BlobMetadata;
-import org.jclouds.blobstore.domain.MutableBlobMetadata;
-import org.jclouds.blobstore.domain.MutableStorageMetadata;
-import org.jclouds.blobstore.domain.PageSet;
-import org.jclouds.blobstore.domain.StorageMetadata;
-import org.jclouds.blobstore.domain.StorageType;
-import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
-import org.jclouds.blobstore.domain.internal.PageSetImpl;
-import org.jclouds.blobstore.domain.internal.StorageMetadataImpl;
-import org.jclouds.blobstore.internal.BaseAsyncBlobStore;
-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.blobstore.strategy.IfDirectoryReturnNameStrategy;
-import org.jclouds.blobstore.util.BlobStoreUtils;
-import org.jclouds.blobstore.util.BlobUtils;
-import org.jclouds.collect.Memoized;
-import org.jclouds.domain.Location;
-import org.jclouds.http.HttpCommand;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.http.HttpUtils;
-import org.jclouds.io.ByteStreams2;
-import org.jclouds.io.ContentMetadata;
-import org.jclouds.io.ContentMetadataCodec;
-import org.jclouds.io.Payload;
-import org.jclouds.logging.Logger;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-
-/**
- * Implementation of {@link BaseAsyncBlobStore} which uses a pluggable
- * LocalStorageStrategy.
- *
- * @deprecated will be removed in jclouds 1.7, as async interfaces are no longer
- *             supported. Please create and use {@link LocalBlobStore}
- */
-@Deprecated
-public class LocalAsyncBlobStore extends BaseAsyncBlobStore {
-
-   @Resource
-   protected Logger logger = Logger.NULL;
-
-   protected final ContentMetadataCodec contentMetadataCodec;
-   protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
-   protected final Factory blobFactory;
-   protected final LocalStorageStrategy storageStrategy;
-
-   @Inject
-   protected LocalAsyncBlobStore(BlobStoreContext context,
-         BlobUtils blobUtils,
-         @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-         Supplier<Location> defaultLocation,
-         @Memoized Supplier<Set<? extends Location>> locations,
-         ContentMetadataCodec contentMetadataCodec,
-         IfDirectoryReturnNameStrategy ifDirectoryReturnName,
-         Factory blobFactory, LocalStorageStrategy storageStrategy) {
-      super(context, blobUtils, userExecutor, defaultLocation, locations);
-      this.blobFactory = blobFactory;
-      this.contentMetadataCodec = contentMetadataCodec;
-      this.ifDirectoryReturnName = ifDirectoryReturnName;
-      this.storageStrategy = storageStrategy;
-   }
-
-   /**
-    * default maxResults is 1000
-    */
-   @Override
-   public ListenableFuture<PageSet<? extends StorageMetadata>> list(final String container, ListContainerOptions options) {
-
-      // Check if the container exists
-      if (!storageStrategy.containerExists(container))
-         return immediateFailedFuture(cnfe(container));
-
-      // Loading blobs from container
-      Iterable<String> blobBelongingToContainer = null;
-      try {
-         blobBelongingToContainer = storageStrategy.getBlobKeysInsideContainer(container);
-      } catch (IOException e) {
-         logger.error(e, "An error occurred loading blobs contained into container %s", container);
-         Throwables.propagate(e);
-      }
-
-      SortedSet<StorageMetadata> contents = newTreeSet(transform(blobBelongingToContainer,
-            new Function<String, StorageMetadata>() {
-               public StorageMetadata apply(String key) {
-                  if (!storageStrategy.blobExists(container, key)) {
-                     // handle directory
-                     return new StorageMetadataImpl(StorageType.FOLDER, /*id=*/ null, key,
-                           /*location=*/ null, /*uri=*/ null, /*eTag=*/ null, /*creationDate=*/ null,
-                           /*lastModified=*/ null, ImmutableMap.<String, String>of());
-                  }
-                  Blob oldBlob = loadBlob(container, key);
-                  checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
-                        + container);
-                  checkState(oldBlob.getMetadata() != null, "blob " + container + "/" + key + " has no metadata");
-                  MutableBlobMetadata md = BlobStoreUtils.copy(oldBlob.getMetadata());
-                  String directoryName = ifDirectoryReturnName.execute(md);
-                  if (directoryName != null) {
-                     md.setName(directoryName);
-                     md.setType(StorageType.RELATIVE_PATH);
-                  }
-                  return md;
-               }
-            }));
-
-      String marker = null;
-      if (options != null) {
-         if (options.getMarker() != null) {
-            final String finalMarker = options.getMarker();
-            StorageMetadata lastMarkerMetadata = find(contents, new Predicate<StorageMetadata>() {
-               public boolean apply(StorageMetadata metadata) {
-                  return metadata.getName().compareTo(finalMarker) > 0;
-               }
-            });
-            contents = contents.tailSet(lastMarkerMetadata);
-         }
-
-         final String prefix = options.getDir();
-         if (prefix != null) {
-            contents = newTreeSet(filter(contents, new Predicate<StorageMetadata>() {
-               public boolean apply(StorageMetadata o) {
-                  return o != null && o.getName().startsWith(prefix) && !o.getName().equals(prefix);
-               }
-            }));
-         }
-
-         int maxResults = options.getMaxResults() != null ? options.getMaxResults() : 1000;
-         if (!contents.isEmpty()) {
-            StorageMetadata lastElement = contents.last();
-            contents = newTreeSet(Iterables.limit(contents, maxResults));
-            if (!contents.contains(lastElement)) {
-               // Partial listing
-               marker = contents.last().getName();
-            }
-         }
-
-         if (!options.isRecursive()) {
-            String delimiter = storageStrategy.getSeparator();
-            SortedSet<String> commonPrefixes = newTreeSet(
-                   transform(contents, new CommonPrefixes(prefix, delimiter)));
-            commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
-
-            contents = newTreeSet(filter(contents, new DelimiterFilter(prefix, delimiter)));
-
-            for (String o : commonPrefixes) {
-               MutableStorageMetadata md = new MutableStorageMetadataImpl();
-               md.setType(StorageType.RELATIVE_PATH);
-               md.setName(o);
-               contents.add(md);
-            }
-         }
-
-         // trim metadata, if the response isn't supposed to be detailed.
-         if (!options.isDetailed()) {
-            for (StorageMetadata md : contents) {
-               md.getUserMetadata().clear();
-            }
-         }
-      }
-
-      return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(contents,
-            marker));
-
-   }
-
-   private ContainerNotFoundException cnfe(final String name) {
-      return new ContainerNotFoundException(name, String.format(
-            "container %s not in %s", name,
-            storageStrategy.getAllContainerNames()));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Void> removeBlob(final String container, final String key) {
-      if (!storageStrategy.containerExists(container)) {
-         return Futures.immediateFailedFuture(cnfe(container));
-      }
-      storageStrategy.removeBlob(container, key);
-      return immediateFuture(null);
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Void> clearContainer(final String container) {
-      storageStrategy.clearContainer(container);
-      return immediateFuture(null);
-   }
-
-   /**
-    * Override parent method because it uses strange futures and listenables
-    * that creates problem in the test if more than one test that deletes the
-    * container is executed
-    *
-    * @param container
-    * @return
-    */
-   @Override
-   public ListenableFuture<Void> deleteContainer(final String container) {
-      deleteAndVerifyContainerGone(container);
-      return immediateFuture(null);
-   }
-
-   @Override
-   public ListenableFuture<Boolean> deleteContainerIfEmpty(final String container) {
-      Boolean returnVal = true;
-      if (storageStrategy.containerExists(container)) {
-         try {
-            if (Iterables.isEmpty(storageStrategy.getBlobKeysInsideContainer(container)))
-               storageStrategy.deleteContainer(container);
-            else
-               returnVal = false;
-         } catch (IOException e) {
-            logger.error(e, "An error occurred loading blobs contained into container %s", container);
-            Throwables.propagate(e);
-         }
-      }
-      return immediateFuture(returnVal);
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Boolean> containerExists(final String containerName) {
-      return immediateFuture(storageStrategy.containerExists(containerName));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<PageSet<? extends StorageMetadata>> list() {
-      Iterable<String> containers = storageStrategy.getAllContainerNames();
-
-      return Futures.<PageSet<? extends StorageMetadata>> immediateFuture(new PageSetImpl<StorageMetadata>(transform(
-            containers, new Function<String, StorageMetadata>() {
-               public StorageMetadata apply(String name) {
-                  MutableStorageMetadata cmd = create();
-                  cmd.setName(name);
-                  cmd.setType(StorageType.CONTAINER);
-                  cmd.setLocation(storageStrategy.getLocation(name));
-                  return cmd;
-               }
-            }), null));
-   }
-
-   protected MutableStorageMetadata create() {
-      return new MutableStorageMetadataImpl();
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Boolean> createContainerInLocation(final Location location,
-         final String name) {
-      boolean result = storageStrategy.createContainerInLocation(name, location);
-      return immediateFuture(result);
-   }
-
-   private Blob loadBlob(final String container, final String key) {
-      logger.debug("Opening blob in container: %s - %s", container, key);
-      return storageStrategy.getBlob(container, key);
-   }
-
-   protected static class DelimiterFilter implements Predicate<StorageMetadata> {
-      private final String prefix;
-      private final String delimiter;
-
-      public DelimiterFilter(String prefix, String delimiter) {
-         this.prefix = prefix;
-         this.delimiter = delimiter;
-      }
-
-      public boolean apply(StorageMetadata metadata) {
-         if (prefix == null)
-            return metadata.getName().indexOf(delimiter) == -1;
-         // ensure we don't accidentally append twice
-         String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
-         if (metadata.getName().startsWith(toMatch)) {
-            String unprefixedName = metadata.getName().replaceFirst(Pattern.quote(toMatch), "");
-            if (unprefixedName.equals("")) {
-               // we are the prefix in this case, return false
-               return false;
-            }
-            return unprefixedName.indexOf(delimiter) == -1;
-         }
-         return false;
-      }
-   }
-
-   protected static class CommonPrefixes implements Function<StorageMetadata, String> {
-      private final String prefix;
-      private final String delimiter;
-      public static final String NO_PREFIX = "NO_PREFIX";
-
-      public CommonPrefixes(String prefix, String delimiter) {
-         this.prefix = prefix;
-         this.delimiter = delimiter;
-      }
-
-      public String apply(StorageMetadata metadata) {
-         String working = metadata.getName();
-         if (prefix != null) {
-            // ensure we don't accidentally append twice
-            String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
-            if (working.startsWith(toMatch)) {
-               working = working.replaceFirst(Pattern.quote(toMatch), "");
-            }
-         }
-         if (working.contains(delimiter)) {
-            return working.substring(0, working.indexOf(delimiter));
-         }
-         return NO_PREFIX;
-      }
-   }
-
-   public static HttpResponseException returnResponseException(int code) {
-      HttpResponse response = HttpResponse.builder().statusCode(code).build();
-      return new HttpResponseException(new HttpCommand(HttpRequest.builder().method("GET").endpoint("http://stub")
-            .build()), response);
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<String> putBlob(String containerName, Blob blob) {
-      checkNotNull(containerName, "containerName must be set");
-      checkNotNull(blob, "blob must be set");
-      String blobKey = blob.getMetadata().getName();
-
-      logger.debug("Put blob with key [%s] to container [%s]", blobKey, containerName);
-      if (!storageStrategy.containerExists(containerName)) {
-         return Futures.immediateFailedFuture(cnfe(containerName));
-      }
-
-      try {
-         return immediateFuture(storageStrategy.putBlob(containerName, blob));
-      } catch (IOException e) {
-         String message = e.getMessage();
-         if (message != null && message.startsWith("MD5 hash code mismatch")) {
-            HttpResponseException exception = returnResponseException(400);
-            exception.initCause(e);
-            throw exception;
-         }
-         logger.error(e, "An error occurred storing the new blob with name [%s] to container [%s].", blobKey,
-               containerName);
-         throw Throwables.propagate(e);
-      }
-   }
-
-   private void copyPayloadHeadersToBlob(Payload payload, Blob blob) {
-      blob.getAllHeaders().putAll(contentMetadataCodec.toHeaders(payload.getContentMetadata()));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Boolean> blobExists(final String containerName, final String key) {
-      if (!storageStrategy.containerExists(containerName))
-         return immediateFailedFuture(cnfe(containerName));
-      return immediateFuture(storageStrategy.blobExists(containerName, key));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<Blob> getBlob(final String containerName, final String key, GetOptions options) {
-      logger.debug("Retrieving blob with key %s from container %s", key, containerName);
-      // If the container doesn't exist, an exception is thrown
-      if (!storageStrategy.containerExists(containerName)) {
-         logger.debug("Container %s does not exist", containerName);
-         return immediateFailedFuture(cnfe(containerName));
-      }
-      // If the blob doesn't exist, a null object is returned
-      if (!storageStrategy.blobExists(containerName, key)) {
-         logger.debug("Item %s does not exist in container %s", key, containerName);
-         return immediateFuture(null);
-      }
-
-      Blob blob = loadBlob(containerName, key);
-
-      if (options != null) {
-         if (options.getIfMatch() != null) {
-            if (!blob.getMetadata().getETag().equals(options.getIfMatch()))
-               return immediateFailedFuture(returnResponseException(412));
-         }
-         if (options.getIfNoneMatch() != null) {
-            if (blob.getMetadata().getETag().equals(options.getIfNoneMatch()))
-               return immediateFailedFuture(returnResponseException(304));
-         }
-         if (options.getIfModifiedSince() != null) {
-            Date modifiedSince = options.getIfModifiedSince();
-            if (blob.getMetadata().getLastModified().before(modifiedSince)) {
-               HttpResponse response = HttpResponse.builder().statusCode(304).build();
-               return immediateFailedFuture(new HttpResponseException(String.format("%1$s is before %2$s", blob
-                     .getMetadata().getLastModified(), modifiedSince), null, response));
-            }
-
-         }
-         if (options.getIfUnmodifiedSince() != null) {
-            Date unmodifiedSince = options.getIfUnmodifiedSince();
-            if (blob.getMetadata().getLastModified().after(unmodifiedSince)) {
-               HttpResponse response = HttpResponse.builder().statusCode(412).build();
-               return immediateFailedFuture(new HttpResponseException(String.format("%1$s is after %2$s", blob
-                     .getMetadata().getLastModified(), unmodifiedSince), null, response));
-            }
-         }
-         blob = copyBlob(blob);
-
-         if (options.getRanges() != null && !options.getRanges().isEmpty()) {
-            byte[] data;
-            try {
-               data = ByteStreams2.toByteArrayAndClose(blob.getPayload().openStream());
-            } catch (IOException e) {
-               return immediateFailedFuture(new RuntimeException(e));
-            }
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            for (String s : options.getRanges()) {
-               // HTTP uses a closed interval while Java array indexing uses a
-               // half-open interval.
-               int offset = 0;
-               int last = data.length - 1;
-               if (s.startsWith("-")) {
-                  offset = last - Integer.parseInt(s.substring(1)) + 1;
-               } else if (s.endsWith("-")) {
-                  offset = Integer.parseInt(s.substring(0, s.length() - 1));
-               } else if (s.contains("-")) {
-                  String[] firstLast = s.split("\\-");
-                  offset = Integer.parseInt(firstLast[0]);
-                  last = Integer.parseInt(firstLast[1]);
-               } else {
-                  return immediateFailedFuture(new IllegalArgumentException("illegal range: " + s));
-               }
-
-               if (offset > last) {
-                  return immediateFailedFuture(new IllegalArgumentException("illegal range: " + s));
-               }
-               if (last + 1 > data.length) {
-                  last = data.length - 1;
-               }
-               out.write(data, offset, last - offset + 1);
-            }
-            ContentMetadata cmd = blob.getPayload().getContentMetadata();
-            byte[] byteArray = out.toByteArray();
-            blob.setPayload(byteArray);
-            HttpUtils.copy(cmd, blob.getPayload().getContentMetadata());
-            blob.getPayload().getContentMetadata().setContentLength(Long.valueOf(byteArray.length));
-         }
-      }
-      checkNotNull(blob.getPayload(), "payload " + blob);
-      return immediateFuture(blob);
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public ListenableFuture<BlobMetadata> blobMetadata(final String container, final String key) {
-      try {
-         Blob blob = getBlob(container, key).get();
-         return immediateFuture(blob != null ? (BlobMetadata) BlobStoreUtils.copy(blob.getMetadata()) : null);
-      } catch (Exception e) {
-         if (size(filter(getCausalChain(e), KeyNotFoundException.class)) >= 1)
-            return immediateFuture(null);
-         return immediateFailedFuture(e);
-      }
-   }
-
-   private Blob copyBlob(Blob blob) {
-      Blob returnVal = blobFactory.create(BlobStoreUtils.copy(blob.getMetadata()));
-      returnVal.setPayload(blob.getPayload());
-      copyPayloadHeadersToBlob(blob.getPayload(), returnVal);
-      return returnVal;
-   }
-
-   @Override
-   protected boolean deleteAndVerifyContainerGone(final String container) {
-      storageStrategy.deleteContainer(container);
-      return storageStrategy.containerExists(container);
-   }
-
-   @Override
-   public ListenableFuture<String> putBlob(String container, Blob blob, PutOptions options) {
-      // TODO implement options
-      return putBlob(container, blob);
-   }
-
-   @Override
-   public ListenableFuture<Boolean> createContainerInLocation(Location location, String container,
-         CreateContainerOptions options) {
-      if (options.isPublicRead())
-         throw new UnsupportedOperationException("publicRead");
-      return createContainerInLocation(location, container);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
index 5245db6..8af40e9 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
@@ -16,8 +16,568 @@
  */
 package org.jclouds.blobstore.config;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Throwables.getCausalChain;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.collect.Iterables.find;
+import static com.google.common.collect.Iterables.size;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.filter;
+import static com.google.common.collect.Sets.newTreeSet;
+import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.regex.Pattern;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.BlobStoreContext;
+import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.blobstore.KeyNotFoundException;
+import org.jclouds.blobstore.LocalStorageStrategy;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.BlobBuilder;
+import org.jclouds.blobstore.domain.BlobMetadata;
+import org.jclouds.blobstore.domain.MutableBlobMetadata;
+import org.jclouds.blobstore.domain.MutableStorageMetadata;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
+import org.jclouds.blobstore.domain.internal.PageSetImpl;
+import org.jclouds.blobstore.domain.internal.StorageMetadataImpl;
+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.blobstore.strategy.IfDirectoryReturnNameStrategy;
+import org.jclouds.blobstore.util.BlobStoreUtils;
+import org.jclouds.blobstore.util.BlobUtils;
+import org.jclouds.collect.Memoized;
+import org.jclouds.domain.Location;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.io.ByteStreams2;
+import org.jclouds.io.ContentMetadata;
+import org.jclouds.io.ContentMetadataCodec;
+import org.jclouds.io.Payload;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+@Singleton
+public final class LocalBlobStore implements BlobStore {
+
+   @Resource
+   private Logger logger = Logger.NULL;
+
+   private final BlobStoreContext context;
+   private final BlobUtils blobUtils;
+   private final Supplier<Set<? extends Location>> locations;
+   private final ContentMetadataCodec contentMetadataCodec;
+   private final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
+   private final Blob.Factory blobFactory;
+   private final LocalStorageStrategy storageStrategy;
+
+   @Inject
+   LocalBlobStore(BlobStoreContext context,
+         BlobUtils blobUtils,
+         @Memoized Supplier<Set<? extends Location>> locations,
+         ContentMetadataCodec contentMetadataCodec,
+         IfDirectoryReturnNameStrategy ifDirectoryReturnName,
+         Blob.Factory blobFactory, LocalStorageStrategy storageStrategy) {
+      this.context = checkNotNull(context, "context");
+      this.blobUtils = checkNotNull(blobUtils, "blobUtils");
+      this.locations = checkNotNull(locations, "locations");
+      this.blobFactory = blobFactory;
+      this.contentMetadataCodec = contentMetadataCodec;
+      this.ifDirectoryReturnName = ifDirectoryReturnName;
+      this.storageStrategy = storageStrategy;
+   }
+
+   @Override
+   public BlobStoreContext getContext() {
+      return context;
+   }
+
+   @Override
+   public BlobBuilder blobBuilder(String name) {
+      return blobUtils.blobBuilder().name(name);
+   }
+
+   /** This implementation invokes {@link #list(String, ListContainerOptions)} */
+   @Override
+   public PageSet<? extends StorageMetadata> list(String containerName) {
+      return this.list(containerName, ListContainerOptions.NONE);
+   }
+
+   /**
+    * This implementation invokes {@link #countBlobs} with the
+    * {@link ListContainerOptions#recursive} option.
+    */
+   @Override
+   public long countBlobs(String containerName) {
+      return countBlobs(containerName, recursive());
+   }
+
+   /**
+    * This implementation invokes {@link BlobUtils#countBlobs}
+    */
+   @Override
+   public long countBlobs(final String containerName, final ListContainerOptions options) {
+      return blobUtils.countBlobs(containerName, options);
+   }
+
+   /**
+    * This implementation invokes {@link #clearContainer} with the
+    * {@link ListContainerOptions#recursive} option.
+    */
+   @Override
+   public void clearContainer(String containerName) {
+      clearContainer(containerName, recursive());
+   }
+
+   @Override
+   public void clearContainer(String containerName, ListContainerOptions options) {
+      blobUtils.clearContainer(containerName, options);
+   }
+
+   @Override
+   public void deleteDirectory(final String containerName, final String directory) {
+      blobUtils.deleteDirectory(containerName, directory);
+   }
+
+   @Override
+   public boolean directoryExists(String containerName, String directory) {
+      return blobUtils.directoryExists(containerName, directory);
+   }
+
+   @Override
+   public void createDirectory(String containerName, String directory) {
+      if (!blobUtils.directoryExists(containerName, directory)) {
+         blobUtils.createDirectory(containerName, directory);
+      }
+   }
+
+   /**
+    * This implementation invokes {@link #getBlob(String,String, GetOptions)}
+    */
+   @Override
+   public Blob getBlob(String containerName, String key) {
+      return getBlob(containerName, key, GetOptions.NONE);
+   }
+
+   /**
+    * This implementation invokes {@link #deleteAndVerifyContainerGone}
+    */
+   @Override
+   public void deleteContainer(String containerName) {
+      deleteAndVerifyContainerGone(containerName);
+   }
+
+   @Override
+   public Set<? extends Location> listAssignableLocations() {
+      return locations.get();
+   }
+
+   /**
+    * default maxResults is 1000
+    */
+   @Override
+   public PageSet<? extends StorageMetadata> list(final String containerName, ListContainerOptions options) {
+
+      // Check if the container exists
+      if (!storageStrategy.containerExists(containerName))
+         throw cnfe(containerName);
+
+      // Loading blobs from container
+      Iterable<String> blobBelongingToContainer = null;
+      try {
+         blobBelongingToContainer = storageStrategy.getBlobKeysInsideContainer(containerName);
+      } catch (IOException e) {
+         logger.error(e, "An error occurred loading blobs contained into container %s", containerName);
+         propagate(e);
+      }
+
+      SortedSet<StorageMetadata> contents = newTreeSet(transform(blobBelongingToContainer,
+            new Function<String, StorageMetadata>() {
+               public StorageMetadata apply(String key) {
+                  if (!storageStrategy.blobExists(containerName, key)) {
+                     // handle directory
+                     return new StorageMetadataImpl(StorageType.FOLDER, /*id=*/ null, key,
+                           /*location=*/ null, /*uri=*/ null, /*eTag=*/ null, /*creationDate=*/ null,
+                           /*lastModified=*/ null, ImmutableMap.<String, String>of());
+                  }
+                  Blob oldBlob = loadBlob(containerName, key);
+                  checkState(oldBlob != null, "blob " + key + " is not present although it was in the list of "
+                        + containerName);
+                  checkState(oldBlob.getMetadata() != null, "blob " + containerName + "/" + key + " has no metadata");
+                  MutableBlobMetadata md = BlobStoreUtils.copy(oldBlob.getMetadata());
+                  String directoryName = ifDirectoryReturnName.execute(md);
+                  if (directoryName != null) {
+                     md.setName(directoryName);
+                     md.setType(StorageType.RELATIVE_PATH);
+                  }
+                  return md;
+               }
+            }));
+
+      String marker = null;
+      if (options != null) {
+         if (options.getMarker() != null) {
+            final String finalMarker = options.getMarker();
+            StorageMetadata lastMarkerMetadata = find(contents, new Predicate<StorageMetadata>() {
+               public boolean apply(StorageMetadata metadata) {
+                  return metadata.getName().compareTo(finalMarker) > 0;
+               }
+            });
+            contents = contents.tailSet(lastMarkerMetadata);
+         }
+
+         final String prefix = options.getDir();
+         if (prefix != null) {
+            contents = newTreeSet(filter(contents, new Predicate<StorageMetadata>() {
+               public boolean apply(StorageMetadata o) {
+                  return o != null && o.getName().startsWith(prefix) && !o.getName().equals(prefix);
+               }
+            }));
+         }
+
+         int maxResults = options.getMaxResults() != null ? options.getMaxResults() : 1000;
+         if (!contents.isEmpty()) {
+            StorageMetadata lastElement = contents.last();
+            contents = newTreeSet(Iterables.limit(contents, maxResults));
+            if (!contents.contains(lastElement)) {
+               // Partial listing
+               marker = contents.last().getName();
+            }
+         }
+
+         if (!options.isRecursive()) {
+            String delimiter = storageStrategy.getSeparator();
+            SortedSet<String> commonPrefixes = newTreeSet(
+                  transform(contents, new CommonPrefixes(prefix, delimiter)));
+            commonPrefixes.remove(CommonPrefixes.NO_PREFIX);
+
+            contents = newTreeSet(filter(contents, new DelimiterFilter(prefix, delimiter)));
+
+            for (String o : commonPrefixes) {
+               MutableStorageMetadata md = new MutableStorageMetadataImpl();
+               md.setType(StorageType.RELATIVE_PATH);
+               md.setName(o);
+               contents.add(md);
+            }
+         }
+
+         // trim metadata, if the response isn't supposed to be detailed.
+         if (!options.isDetailed()) {
+            for (StorageMetadata md : contents) {
+               md.getUserMetadata().clear();
+            }
+         }
+      }
+
+      return new PageSetImpl<StorageMetadata>(contents, marker);
+   }
+
+   private ContainerNotFoundException cnfe(final String name) {
+      return new ContainerNotFoundException(name, String.format(
+            "container %s not in %s", name,
+            storageStrategy.getAllContainerNames()));
+   }
+
+   @Override
+   public void removeBlob(String containerName, final String key) {
+      if (!storageStrategy.containerExists(containerName)) {
+         throw cnfe(containerName);
+      }
+      storageStrategy.removeBlob(containerName, key);
+   }
+
+   @Override
+   public boolean deleteContainerIfEmpty(String containerName) {
+      boolean returnVal = true;
+      if (storageStrategy.containerExists(containerName)) {
+         try {
+            if (Iterables.isEmpty(storageStrategy.getBlobKeysInsideContainer(containerName)))
+               storageStrategy.deleteContainer(containerName);
+            else
+               returnVal = false;
+         } catch (IOException e) {
+            logger.error(e, "An error occurred loading blobs contained into container %s", containerName);
+            throw propagate(e);
+         }
+      }
+      return returnVal;
+   }
+
+   @Override
+   public boolean containerExists(String containerName) {
+      return storageStrategy.containerExists(containerName);
+   }
+
+   @Override
+   public PageSet<? extends StorageMetadata> list() {
+      Iterable<String> containers = storageStrategy.getAllContainerNames();
+
+      return new PageSetImpl<StorageMetadata>(transform(
+            containers, new Function<String, StorageMetadata>() {
+               public StorageMetadata apply(String name) {
+                  MutableStorageMetadata cmd = create();
+                  cmd.setName(name);
+                  cmd.setType(StorageType.CONTAINER);
+                  cmd.setLocation(storageStrategy.getLocation(name));
+                  return cmd;
+               }
+            }), null);
+   }
+
+   private MutableStorageMetadata create() {
+      return new MutableStorageMetadataImpl();
+   }
+
+   @Override
+   public boolean createContainerInLocation(Location location, String name) {
+      return storageStrategy.createContainerInLocation(name, location);
+   }
+
+   private Blob loadBlob(final String container, final String key) {
+      logger.debug("Opening blob in container: %s - %s", container, key);
+      return storageStrategy.getBlob(container, key);
+   }
+
+   private static class DelimiterFilter implements Predicate<StorageMetadata> {
+      private final String prefix;
+      private final String delimiter;
+
+      public DelimiterFilter(String prefix, String delimiter) {
+         this.prefix = prefix;
+         this.delimiter = delimiter;
+      }
+
+      public boolean apply(StorageMetadata metadata) {
+         if (prefix == null)
+            return metadata.getName().indexOf(delimiter) == -1;
+         // ensure we don't accidentally append twice
+         String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
+         if (metadata.getName().startsWith(toMatch)) {
+            String unprefixedName = metadata.getName().replaceFirst(Pattern.quote(toMatch), "");
+            if (unprefixedName.equals("")) {
+               // we are the prefix in this case, return false
+               return false;
+            }
+            return unprefixedName.indexOf(delimiter) == -1;
+         }
+         return false;
+      }
+   }
+
+   private static class CommonPrefixes implements Function<StorageMetadata, String> {
+      private final String prefix;
+      private final String delimiter;
+      public static final String NO_PREFIX = "NO_PREFIX";
+
+      public CommonPrefixes(String prefix, String delimiter) {
+         this.prefix = prefix;
+         this.delimiter = delimiter;
+      }
+
+      public String apply(StorageMetadata metadata) {
+         String working = metadata.getName();
+         if (prefix != null) {
+            // ensure we don't accidentally append twice
+            String toMatch = prefix.endsWith("/") ? prefix : prefix + delimiter;
+            if (working.startsWith(toMatch)) {
+               working = working.replaceFirst(Pattern.quote(toMatch), "");
+            }
+         }
+         if (working.contains(delimiter)) {
+            return working.substring(0, working.indexOf(delimiter));
+         }
+         return NO_PREFIX;
+      }
+   }
+
+   private static HttpResponseException returnResponseException(int code) {
+      HttpResponse response = HttpResponse.builder().statusCode(code).build();
+      return new HttpResponseException(new HttpCommand(HttpRequest.builder().method("GET").endpoint("http://stub")
+            .build()), response);
+   }
+
+   @Override
+   public String putBlob(String containerName, Blob blob) {
+      checkNotNull(containerName, "containerName must be set");
+      checkNotNull(blob, "blob must be set");
+      String blobKey = blob.getMetadata().getName();
+
+      logger.debug("Put blob with key [%s] to container [%s]", blobKey, containerName);
+      if (!storageStrategy.containerExists(containerName)) {
+         throw cnfe(containerName);
+      }
+
+      try {
+         return storageStrategy.putBlob(containerName, blob);
+      } catch (IOException e) {
+         String message = e.getMessage();
+         if (message != null && message.startsWith("MD5 hash code mismatch")) {
+            HttpResponseException exception = returnResponseException(400);
+            exception.initCause(e);
+            throw exception;
+         }
+         logger.error(e, "An error occurred storing the new blob with name [%s] to container [%s].", blobKey,
+               containerName);
+         throw propagate(e);
+      }
+   }
+
+   private void copyPayloadHeadersToBlob(Payload payload, Blob blob) {
+      blob.getAllHeaders().putAll(contentMetadataCodec.toHeaders(payload.getContentMetadata()));
+   }
+
+   @Override
+   public boolean blobExists(String containerName, String key) {
+      if (!storageStrategy.containerExists(containerName))
+         throw cnfe(containerName);
+      return storageStrategy.blobExists(containerName, key);
+   }
+
+   @Override
+   public Blob getBlob(String containerName, String key, GetOptions options) {
+      logger.debug("Retrieving blob with key %s from container %s", key, containerName);
+      // If the container doesn't exist, an exception is thrown
+      if (!storageStrategy.containerExists(containerName)) {
+         logger.debug("Container %s does not exist", containerName);
+         throw cnfe(containerName);
+      }
+      // If the blob doesn't exist, a null object is returned
+      if (!storageStrategy.blobExists(containerName, key)) {
+         logger.debug("Item %s does not exist in container %s", key, containerName);
+         return null;
+      }
+
+      Blob blob = loadBlob(containerName, key);
+
+      if (options != null) {
+         if (options.getIfMatch() != null) {
+            if (!blob.getMetadata().getETag().equals(options.getIfMatch()))
+               throw returnResponseException(412);
+         }
+         if (options.getIfNoneMatch() != null) {
+            if (blob.getMetadata().getETag().equals(options.getIfNoneMatch()))
+               throw returnResponseException(304);
+         }
+         if (options.getIfModifiedSince() != null) {
+            Date modifiedSince = options.getIfModifiedSince();
+            if (blob.getMetadata().getLastModified().before(modifiedSince)) {
+               HttpResponse response = HttpResponse.builder().statusCode(304).build();
+               throw new HttpResponseException(String.format("%1$s is before %2$s", blob
+                     .getMetadata().getLastModified(), modifiedSince), null, response);
+            }
+
+         }
+         if (options.getIfUnmodifiedSince() != null) {
+            Date unmodifiedSince = options.getIfUnmodifiedSince();
+            if (blob.getMetadata().getLastModified().after(unmodifiedSince)) {
+               HttpResponse response = HttpResponse.builder().statusCode(412).build();
+               throw new HttpResponseException(String.format("%1$s is after %2$s", blob
+                     .getMetadata().getLastModified(), unmodifiedSince), null, response);
+            }
+         }
+         blob = copyBlob(blob);
+
+         if (options.getRanges() != null && !options.getRanges().isEmpty()) {
+            byte[] data;
+            try {
+               data = ByteStreams2.toByteArrayAndClose(blob.getPayload().openStream());
+            } catch (IOException e) {
+               throw new RuntimeException(e);
+            }
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            for (String s : options.getRanges()) {
+               // HTTP uses a closed interval while Java array indexing uses a
+               // half-open interval.
+               int offset = 0;
+               int last = data.length - 1;
+               if (s.startsWith("-")) {
+                  offset = last - Integer.parseInt(s.substring(1)) + 1;
+               } else if (s.endsWith("-")) {
+                  offset = Integer.parseInt(s.substring(0, s.length() - 1));
+               } else if (s.contains("-")) {
+                  String[] firstLast = s.split("\\-");
+                  offset = Integer.parseInt(firstLast[0]);
+                  last = Integer.parseInt(firstLast[1]);
+               } else {
+                  throw new IllegalArgumentException("illegal range: " + s);
+               }
+
+               if (offset > last) {
+                  throw new IllegalArgumentException("illegal range: " + s);
+               }
+               if (last + 1 > data.length) {
+                  last = data.length - 1;
+               }
+               out.write(data, offset, last - offset + 1);
+            }
+            ContentMetadata cmd = blob.getPayload().getContentMetadata();
+            byte[] byteArray = out.toByteArray();
+            blob.setPayload(byteArray);
+            HttpUtils.copy(cmd, blob.getPayload().getContentMetadata());
+            blob.getPayload().getContentMetadata().setContentLength(Long.valueOf(byteArray.length));
+         }
+      }
+      checkNotNull(blob.getPayload(), "payload " + blob);
+      return blob;
+   }
+
+   @Override
+   public BlobMetadata blobMetadata(String containerName, String key) {
+      try {
+         Blob blob = getBlob(containerName, key);
+         return blob != null ? (BlobMetadata) BlobStoreUtils.copy(blob.getMetadata()) : null;
+      } catch (Exception e) {
+         if (size(Iterables.filter(getCausalChain(e), KeyNotFoundException.class)) >= 1)
+            return null;
+         throw e;
+      }
+   }
+
+   private Blob copyBlob(Blob blob) {
+      Blob returnVal = blobFactory.create(BlobStoreUtils.copy(blob.getMetadata()));
+      returnVal.setPayload(blob.getPayload());
+      copyPayloadHeadersToBlob(blob.getPayload(), returnVal);
+      return returnVal;
+   }
+
+   private boolean deleteAndVerifyContainerGone(final String container) {
+      storageStrategy.deleteContainer(container);
+      return storageStrategy.containerExists(container);
+   }
 
-public interface LocalBlobStore extends BlobStore {
+   @Override
+   public String putBlob(String containerName, Blob blob, PutOptions options) {
+      // TODO implement options
+      return putBlob(containerName, blob);
+   }
 
+   @Override
+   public boolean createContainerInLocation(Location location, String container, CreateContainerOptions options) {
+      if (options.isPublicRead())
+         throw new UnsupportedOperationException("publicRead");
+      return createContainerInLocation(location, container);
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java
index 2f73741..7df30b5 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/config/TransientBlobStoreContextModule.java
@@ -16,12 +16,8 @@
  */
 package org.jclouds.blobstore.config;
 
-import static org.jclouds.rest.config.BinderUtils.bindSyncToAsyncApi;
-
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
-import org.jclouds.blobstore.LocalAsyncBlobStore;
 import org.jclouds.blobstore.LocalBlobRequestSigner;
 import org.jclouds.blobstore.LocalStorageStrategy;
 import org.jclouds.blobstore.TransientStorageStrategy;
@@ -29,15 +25,9 @@ import org.jclouds.blobstore.attr.ConsistencyModel;
 
 import com.google.inject.AbstractModule;
 
-/**
- * Configures the {@link TransientBlobStoreContext}; requires {@link TransientAsyncBlobStore} bound.
- */
 public class TransientBlobStoreContextModule extends AbstractModule {
    @Override
    protected void configure() {
-      bind(AsyncBlobStore.class).to(LocalAsyncBlobStore.class).asEagerSingleton();
-      // forward all requests from TransientBlobStore to TransientAsyncBlobStore.  needs above binding as cannot proxy a class
-      bindSyncToAsyncApi(binder(), LocalBlobStore.class, AsyncBlobStore.class);
       install(new BlobStoreObjectModule());
       bind(BlobStore.class).to(LocalBlobStore.class);
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java
deleted file mode 100644
index 8bddf7f..0000000
--- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java
+++ /dev/null
@@ -1,310 +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.blobstore.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
-import static org.jclouds.util.Predicates2.retry;
-
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.Constants;
-import org.jclouds.blobstore.AsyncBlobStore;
-import org.jclouds.blobstore.BlobStoreContext;
-import org.jclouds.blobstore.ContainerNotFoundException;
-import org.jclouds.blobstore.domain.Blob;
-import org.jclouds.blobstore.domain.BlobBuilder;
-import org.jclouds.blobstore.domain.PageSet;
-import org.jclouds.blobstore.domain.StorageMetadata;
-import org.jclouds.blobstore.options.ListContainerOptions;
-import org.jclouds.blobstore.util.BlobUtils;
-import org.jclouds.collect.Memoized;
-import org.jclouds.domain.Location;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-
-/**
- * 
- * @deprecated will be removed in jclouds 1.7, as async interfaces are no longer
- *             supported. Please use {@link org.jclouds.blobstore.BlobStore}
- */
-@Deprecated
-public abstract class BaseAsyncBlobStore implements AsyncBlobStore {
-
-   protected final BlobStoreContext context;
-   protected final BlobUtils blobUtils;
-   protected final ListeningExecutorService userExecutor;
-   protected final Supplier<Location> defaultLocation;
-   protected final Supplier<Set<? extends Location>> locations;
-
-   @Inject
-   protected BaseAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
-            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, Supplier<Location> defaultLocation,
-            @Memoized Supplier<Set<? extends Location>> locations) {
-      this.context = checkNotNull(context, "context");
-      this.blobUtils = checkNotNull(blobUtils, "blobUtils");
-      this.userExecutor = checkNotNull(userExecutor, "userExecutor");
-      this.defaultLocation = checkNotNull(defaultLocation, "defaultLocation");
-      this.locations = checkNotNull(locations, "locations");
-   }
-
-   @Override
-   public BlobStoreContext getContext() {
-      return context;
-   }
-
-   /**
-    * invokes {@link BlobUtilsImpl#blobBuilder }
-    */
-   @Override
-   public BlobBuilder blobBuilder(String name) {
-      return blobUtils.blobBuilder().name(name);
-   }
-
-   /**
-    * This implementation invokes
-    * {@link #list(String,org.jclouds.blobstore.options.ListContainerOptions)}
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<PageSet<? extends StorageMetadata>> list(String container) {
-      return this.list(container, org.jclouds.blobstore.options.ListContainerOptions.NONE);
-   }
-
-   /**
-    * This implementation invokes {@link #countBlobs} with the
-    * {@link ListContainerOptions#recursive} option.
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<Long> countBlobs(String container) {
-      return countBlobs(container, recursive());
-   }
-
-   /**
-    * This implementation invokes {@link BlobUtilsImpl#countBlobs}
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<Long> countBlobs(final String containerName, final ListContainerOptions options) {
-      return userExecutor.submit(new Callable<Long>() {
-         public Long call() throws Exception {
-            return blobUtils.countBlobs(containerName, options);
-         }
-
-         @Override
-         public String toString() {
-            return "countBlobs(" + containerName + ")";
-         }
-      });
-   }
-
-   /**
-    * This implementation invokes {@link #clearContainer} with the
-    * {@link ListContainerOptions#recursive} option.
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<Void> clearContainer(final String container) {
-      return clearContainer(container, recursive());
-   }
-
-   /**
-    * This implementation invokes {@link BlobUtilsImpl#clearContainer}
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<Void> clearContainer(final String containerName, final ListContainerOptions options) {
-      return userExecutor.submit(new Callable<Void>() {
-
-         public Void call() throws Exception {
-            blobUtils.clearContainer(containerName, options);
-            return null;
-         }
-
-         @Override
-         public String toString() {
-            return "clearContainer(" + containerName + ")";
-         }
-      });
-   }
-
-   /**
-    * This implementation invokes {@link BlobUtilsImpl#deleteDirectory}.
-    * 
-    * @param container
-    *           container name
-    */
-   @Override
-   public ListenableFuture<Void> deleteDirectory(final String containerName, final String directory) {
-      return userExecutor.submit(new Callable<Void>() {
-
-         public Void call() throws Exception {
-            blobUtils.deleteDirectory(containerName, directory);
-            return null;
-         }
-
-         @Override
-         public String toString() {
-            return "deleteDirectory(" + containerName + "," + directory + ")";
-         }
-      });
-   }
-
-   /**
-    * This implementation invokes {@link BlobUtilsImpl#directoryExists}
-    * 
-    * @param container
-    *           container name
-    * @param directory
-    *           virtual path
-    */
-   public ListenableFuture<Boolean> directoryExists(final String containerName, final String directory) {
-      return userExecutor.submit(new Callable<Boolean>() {
-
-         public Boolean call() throws Exception {
-            return blobUtils.directoryExists(containerName, directory);
-         }
-
-         @Override
-         public String toString() {
-            return "directoryExists(" + containerName + "," + directory + ")";
-         }
-      });
-   }
-
-   /**
-    * This implementation invokes {@link BlobUtilsImpl#createDirectory}
-    * 
-    * @param container
-    *           container name
-    * @param directory
-    *           virtual path
-    */
-
-   public ListenableFuture<Void> createDirectory(final String containerName, final String directory) {
-      return blobUtils.directoryExists(containerName, directory) ? Futures.immediateFuture((Void) null)
-               : userExecutor.submit(new Callable<Void>() {
-                  public Void call() throws Exception {
-                     blobUtils.createDirectory(containerName, directory);
-                     return null;
-                  }
-
-                  @Override
-                  public String toString() {
-                     return "createDirectory(" + containerName + "," + directory + ")";
-                  }
-               });
-   }
-
-   /**
-    * This implementation invokes
-    * {@link #getBlob(String,String,org.jclouds.blobstore.options.GetOptions)}
-    * 
-    * @param container
-    *           container name
-    * @param key
-    *           blob key
-    */
-   @Override
-   public ListenableFuture<Blob> getBlob(String container, String key) {
-      return getBlob(container, key, org.jclouds.blobstore.options.GetOptions.NONE);
-   }
-
-   /**
-    * This implementation invokes {@link #deleteAndEnsurePathGone}
-    * 
-    * @param container
-    *           bucket name
-    */
-   @Override
-   public ListenableFuture<Void> deleteContainer(final String container) {
-      return userExecutor.submit(new Callable<Void>() {
-
-         public Void call() throws Exception {
-            deletePathAndEnsureGone(container);
-            return null;
-         }
-
-         @Override
-         public String toString() {
-            return "deleteContainer(" + container + ")";
-         }
-      });
-   }
-
-   @Override
-   public ListenableFuture<Boolean> deleteContainerIfEmpty(final String container) {
-      return userExecutor.submit(new Callable<Boolean>() {
-
-         public Boolean call() throws Exception {
-            return deleteAndVerifyContainerGone(container);
-         }
-
-         @Override
-         public String toString() {
-            return "deleteContainerIfEmpty(" + container + ")";
-         }
-      });
-   }
-
-   protected void deletePathAndEnsureGone(String path) {
-      checkState(retry(new Predicate<String>() {
-         public boolean apply(String in) {
-            try {
-               blobUtils.clearContainer(in, recursive());
-               return deleteAndVerifyContainerGone(in);
-            } catch (ContainerNotFoundException e) {
-               return true;
-            }
-         }
-      }, 30000).apply(path), "%s still exists after deleting!", path);
-   }
-
-   @Override
-   public ListenableFuture<Set<? extends Location>> listAssignableLocations() {
-      return Futures.<Set<? extends Location>> immediateFuture(locations.get());
-   }
-
-   /**
-    * Delete a container if it is empty.
-    *
-    * @param container what to delete
-    * @return true if the container was deleted or does not exist
-    */
-   protected abstract boolean deleteAndVerifyContainerGone(String container);
-
-}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/blobstore/src/test/java/org/jclouds/blobstore/TransientBlobRequestSignerTest.java
----------------------------------------------------------------------
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/TransientBlobRequestSignerTest.java b/blobstore/src/test/java/org/jclouds/blobstore/TransientBlobRequestSignerTest.java
index ff833ab..fb1e89b 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/TransientBlobRequestSignerTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/TransientBlobRequestSignerTest.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import javax.inject.Provider;
 
 import org.jclouds.apis.ApiMetadata;
+import org.jclouds.blobstore.config.LocalBlobStore;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.BlobBuilder;
 import org.jclouds.http.HttpRequest;
@@ -40,7 +41,7 @@ import com.google.common.io.ByteSource;
  */
 // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
 @Test(groups = "unit", testName = "TransientBlobRequestSignerTest")
-public class TransientBlobRequestSignerTest extends BaseAsyncClientTest<LocalAsyncBlobStore> {
+public class TransientBlobRequestSignerTest extends BaseAsyncClientTest<LocalBlobStore> {
 
    private BlobRequestSigner signer;
    private Provider<BlobBuilder> blobFactory;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
index aef156d..9721617 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/config/AzureBlobStoreContextModule.java
@@ -24,11 +24,9 @@ import org.jclouds.azureblob.AzureBlobClient;
 import org.jclouds.azureblob.blobstore.AzureBlobRequestSigner;
 import org.jclouds.azureblob.blobstore.AzureBlobStore;
 import org.jclouds.azureblob.domain.PublicAccess;
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.blobstore.internal.SubmissionAsyncBlobStore;
 
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
@@ -42,7 +40,6 @@ public class AzureBlobStoreContextModule extends AbstractModule {
    @Override
    protected void configure() {
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
-      bind(AsyncBlobStore.class).to(SubmissionAsyncBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobStore.class).to(AzureBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobRequestSigner.class).to(AzureBlobRequestSigner.class);
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/dfb583b6/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
index e33788e..a636b4d 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
@@ -26,10 +26,8 @@ import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
-import org.jclouds.blobstore.internal.SubmissionAsyncBlobStore;
 import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
 import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobStore;
 import org.jclouds.hpcloud.objectstorage.blobstore.functions.HPCloudObjectStorageObjectToBlobMetadata;
@@ -46,7 +44,6 @@ import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.inject.Provides;
-import com.google.inject.Scopes;
 
 public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreContextModule {
 
@@ -96,7 +93,6 @@ public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreCo
    protected void configure() {
       bind(ConsistencyModel.class).toInstance(ConsistencyModel.EVENTUAL);
       bind(BlobStore.class).to(HPCloudObjectStorageBlobStore.class);
-      bind(AsyncBlobStore.class).to(SubmissionAsyncBlobStore.class).in(Scopes.SINGLETON);
       bind(ObjectToBlobMetadata.class).to(HPCloudObjectStorageObjectToBlobMetadata.class);
    }
 }


[2/2] git commit: JCLOUDS-40 Remove internal usage of AsyncBlobStore.

Posted by ad...@apache.org.
JCLOUDS-40 Remove internal usage of AsyncBlobStore.


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

Branch: refs/heads/master
Commit: 56a2a8bf4a0a957db04feeca99610ae1432d7c21
Parents: dfb583b
Author: Adrian Cole <ac...@twitter.com>
Authored: Sat Oct 4 23:02:37 2014 -0700
Committer: Adrian Cole <ad...@gmail.com>
Committed: Sun Oct 5 08:49:54 2014 -0700

----------------------------------------------------------------------
 .../blobstore/CloudFilesBlobStore.java          | 15 ++--
 .../swift/blobstore/SwiftBlobStore.java         | 34 +++++++--
 .../strategy/internal/FetchBlobMetadata.java    | 18 +++--
 .../GetAllBlobsInListAndRetryOnFailure.java     | 18 +++--
 .../MarkersDeleteDirectoryStrategy.java         | 20 +++---
 .../strategy/internal/PutBlobsStrategyImpl.java | 19 +++--
 .../jclouds/blobstore/util/BlobStoreUtils.java  | 24 -------
 .../blobstore/util/BlobStoreUtilsTest.java      | 74 +-------------------
 .../org/jclouds/aws/s3/AWSS3ClientLiveTest.java | 15 ----
 .../HPCloudObjectStorageBlobStore.java          | 27 ++++---
 10 files changed, 104 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/CloudFilesBlobStore.java
----------------------------------------------------------------------
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/CloudFilesBlobStore.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/CloudFilesBlobStore.java
index 7c5979d..96a813b 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/CloudFilesBlobStore.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/CloudFilesBlobStore.java
@@ -16,9 +16,12 @@
  */
 package org.jclouds.cloudfiles.blobstore;
 
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+
 import java.util.Set;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
@@ -38,9 +41,10 @@ import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceList;
 import org.jclouds.openstack.swift.blobstore.functions.ContainerToResourceMetadata;
 import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlob;
 import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
+import org.jclouds.openstack.swift.blobstore.strategy.internal.MultipartUploadStrategy;
 
 import com.google.common.base.Supplier;
-import org.jclouds.openstack.swift.blobstore.strategy.internal.MultipartUploadStrategy;
+import com.google.common.util.concurrent.ListeningExecutorService;
 
 @Singleton
 public class CloudFilesBlobStore extends SwiftBlobStore {
@@ -48,7 +52,8 @@ public class CloudFilesBlobStore extends SwiftBlobStore {
    private EnableCDNAndCache enableCDNAndCache;
 
    @Inject
-   protected CloudFilesBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
+   protected CloudFilesBlobStore(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
+            BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
             @Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
             ContainerToResourceMetadata container2ResourceMd,
             BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
@@ -56,9 +61,9 @@ public class CloudFilesBlobStore extends SwiftBlobStore {
             ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
             Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache,
             Provider<MultipartUploadStrategy> multipartUploadStrategy) {
-      super(context, blobUtils, defaultLocation, locations, sync, container2ResourceMd, container2ContainerListOptions,
-               container2ResourceList, object2Blob, blob2Object, object2BlobMd, blob2ObjectGetOptions,
-               fetchBlobMetadataProvider, multipartUploadStrategy);
+      super(userExecutor, context, blobUtils, defaultLocation, locations, sync, container2ResourceMd,
+            container2ContainerListOptions, container2ResourceList, object2Blob, blob2Object, object2BlobMd,
+            blob2ObjectGetOptions, fetchBlobMetadataProvider, multipartUploadStrategy);
       this.enableCDNAndCache = enableCDNAndCache;
 
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobStore.java
----------------------------------------------------------------------
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobStore.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobStore.java
index 0448909..1cda908 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobStore.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobStore.java
@@ -18,22 +18,23 @@ package org.jclouds.openstack.swift.blobstore;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.jclouds.blobstore.util.BlobStoreUtils.createParentIfNeededAsync;
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
 import static org.jclouds.openstack.swift.options.ListContainerOptions.Builder.withPrefix;
 
 import java.util.Set;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
-import com.google.common.annotations.VisibleForTesting;
 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.PageSetImpl;
+import org.jclouds.blobstore.functions.BlobName;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
 import org.jclouds.blobstore.internal.BaseBlobStore;
 import org.jclouds.blobstore.options.CreateContainerOptions;
@@ -56,13 +57,16 @@ import org.jclouds.openstack.swift.domain.ContainerMetadata;
 import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata;
 import org.jclouds.openstack.swift.domain.ObjectInfo;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Strings;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListeningExecutorService;
 
 @Singleton
 public class SwiftBlobStore extends BaseBlobStore {
+   private final ListeningExecutorService userExecutor;
    private final CommonSwiftClient sync;
    private final ContainerToResourceMetadata container2ResourceMd;
    private final BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions;
@@ -75,7 +79,8 @@ public class SwiftBlobStore extends BaseBlobStore {
    private final Provider<MultipartUploadStrategy> multipartUploadStrategy;
 
    @Inject
-   protected SwiftBlobStore(BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
+   protected SwiftBlobStore(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
+            BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
             @Memoized Supplier<Set<? extends Location>> locations, CommonSwiftClient sync,
             ContainerToResourceMetadata container2ResourceMd,
             BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
@@ -84,6 +89,7 @@ public class SwiftBlobStore extends BaseBlobStore {
             Provider<FetchBlobMetadata> fetchBlobMetadataProvider,
             Provider<MultipartUploadStrategy> multipartUploadStrategy) {
       super(context, blobUtils, defaultLocation, locations);
+      this.userExecutor = userExecutor;
       this.sync = sync;
       this.container2ResourceMd = container2ResourceMd;
       this.container2ContainerListOptions = container2ContainerListOptions;
@@ -196,10 +202,30 @@ public class SwiftBlobStore extends BaseBlobStore {
     */
    @Override
    public String putBlob(String container, Blob blob) {
-      createParentIfNeededAsync(context.getAsyncBlobStore(), container, blob);
+      createParentIfNeededAsync(container, blob);
       return sync.putObject(container, blob2Object.apply(blob));
    }
 
+   private static final BlobName blobName = new BlobName();
+
+   /** Legacy behavior which will not be carried forward in new blobstores. */
+   private void createParentIfNeededAsync(final String containerName, Blob blob) {
+      checkNotNull(containerName, "container");
+      checkNotNull(blob, "blob");
+      final String name = blobName.apply(blob);
+      if (name.indexOf('/') > 0) {
+         userExecutor.submit(new Runnable() {
+            @Override public void run() {
+               createDirectory(containerName, parseDirectoryFromPath(name));
+            }
+         });
+      }
+   }
+
+   private static String parseDirectoryFromPath(String path) {
+      return checkNotNull(path, "path").substring(0, path.lastIndexOf('/'));
+   }
+
    /**
     * This implementation invokes {@link CommonSwiftClient#putObject}
     * 

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
index 560a8f2..79f10a4 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/FetchBlobMetadata.java
@@ -19,11 +19,13 @@ package org.jclouds.blobstore.strategy.internal;
 import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.concurrent.FutureIterables.transformParallel;
 
+import java.util.concurrent.Callable;
+
 import javax.annotation.Resource;
 import javax.inject.Named;
 
 import org.jclouds.Constants;
-import org.jclouds.blobstore.AsyncBlobStore;
+import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.domain.BlobMetadata;
 import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
@@ -49,7 +51,7 @@ import com.google.inject.Inject;
 public class FetchBlobMetadata implements Function<PageSet<? extends StorageMetadata>, PageSet<? extends StorageMetadata>> {
 
    protected final BackoffLimitedRetryHandler retryHandler;
-   protected final AsyncBlobStore ablobstore;
+   protected final BlobStore blobstore;
    protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
@@ -64,10 +66,10 @@ public class FetchBlobMetadata implements Function<PageSet<? extends StorageMeta
    protected Long maxTime;
 
    @Inject
-   FetchBlobMetadata(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, AsyncBlobStore ablobstore,
+   FetchBlobMetadata(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, BlobStore blobstore,
             BackoffLimitedRetryHandler retryHandler) {
       this.userExecutor = userExecutor;
-      this.ablobstore = ablobstore;
+      this.blobstore = blobstore;
       this.retryHandler = retryHandler;
    }
 
@@ -89,8 +91,12 @@ public class FetchBlobMetadata implements Function<PageSet<? extends StorageMeta
       }), new Function<StorageMetadata, ListenableFuture<? extends BlobMetadata>>() {
 
          @Override
-         public ListenableFuture<BlobMetadata> apply(StorageMetadata from) {
-            return ablobstore.blobMetadata(container, from.getName());
+         public ListenableFuture<BlobMetadata> apply(final StorageMetadata from) {
+            return userExecutor.submit(new Callable<BlobMetadata>() {
+               @Override public BlobMetadata call() throws Exception {
+                  return blobstore.blobMetadata(container, from.getName());
+               }
+            });
          }
 
       }, userExecutor, maxTime, logger, String.format("getting metadata from containerName: %s", container)));

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
index b163f3e..158c390 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/GetAllBlobsInListAndRetryOnFailure.java
@@ -18,12 +18,14 @@ package org.jclouds.blobstore.strategy.internal;
 
 import static org.jclouds.concurrent.FutureIterables.transformParallel;
 
+import java.util.concurrent.Callable;
+
 import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.Constants;
-import org.jclouds.blobstore.AsyncBlobStore;
+import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.BlobMetadata;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -47,7 +49,7 @@ public class GetAllBlobsInListAndRetryOnFailure implements GetBlobsInListStrateg
 
    protected final ListBlobsInContainer getAllBlobMetadata;
    protected final BackoffLimitedRetryHandler retryHandler;
-   protected final AsyncBlobStore ablobstore;
+   protected final BlobStore blobstore;
    protected final ListeningExecutorService userExecutor;
    @Resource
    @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
@@ -61,9 +63,9 @@ public class GetAllBlobsInListAndRetryOnFailure implements GetBlobsInListStrateg
 
    @Inject
    GetAllBlobsInListAndRetryOnFailure(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-            ListBlobsInContainer getAllBlobMetadata, AsyncBlobStore ablobstore, BackoffLimitedRetryHandler retryHandler) {
+            ListBlobsInContainer getAllBlobMetadata, BlobStore blobstore, BackoffLimitedRetryHandler retryHandler) {
       this.userExecutor = userExecutor;
-      this.ablobstore = ablobstore;
+      this.blobstore = blobstore;
       this.getAllBlobMetadata = getAllBlobMetadata;
       this.retryHandler = retryHandler;
    }
@@ -73,8 +75,12 @@ public class GetAllBlobsInListAndRetryOnFailure implements GetBlobsInListStrateg
       return transformParallel(list, new Function<BlobMetadata, ListenableFuture<? extends Blob>>() {
 
          @Override
-         public ListenableFuture<Blob> apply(BlobMetadata from) {
-            return ablobstore.getBlob(container, from.getName());
+         public ListenableFuture<Blob> apply(final BlobMetadata from) {
+            return userExecutor.submit(new Callable<Blob>() {
+               @Override public Blob call() throws Exception {
+                  return blobstore.getBlob(container, from.getName());
+               }
+            });
          }
 
       }, userExecutor, maxTime, logger, String.format("getting from containerName: %s", container), retryHandler, 3);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MarkersDeleteDirectoryStrategy.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MarkersDeleteDirectoryStrategy.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MarkersDeleteDirectoryStrategy.java
index 81a6a37..8495227 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MarkersDeleteDirectoryStrategy.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MarkersDeleteDirectoryStrategy.java
@@ -21,6 +21,7 @@ import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Resource;
@@ -28,7 +29,6 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.Constants;
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.internal.BlobRuntimeException;
 import org.jclouds.blobstore.reference.BlobStoreConstants;
@@ -63,7 +63,6 @@ import com.google.inject.Inject;
 @Singleton
 public class MarkersDeleteDirectoryStrategy implements DeleteDirectoryStrategy {
 
-   private final AsyncBlobStore ablobstore;
    private final BlobStore blobstore;
    private final ListeningExecutorService userExecutor;
    @Resource
@@ -77,23 +76,26 @@ public class MarkersDeleteDirectoryStrategy implements DeleteDirectoryStrategy {
    protected Long maxTime;
 
    @Inject
-   MarkersDeleteDirectoryStrategy(
-            @Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-            AsyncBlobStore ablobstore, BlobStore blobstore) {
+   MarkersDeleteDirectoryStrategy(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
+            BlobStore blobstore) {
       this.userExecutor = userExecutor;
-      this.ablobstore = ablobstore;
       this.blobstore = blobstore;
    }
 
-   public void execute(String containerName, String directory) {
+   public void execute(final String containerName, String directory) {
       Set<String> names = Sets.newHashSet();
       names.add(directory);
       for (String suffix : BlobStoreConstants.DIRECTORY_SUFFIXES) {
          names.add(directory + suffix);
       }
       Map<String, ListenableFuture<?>> responses = Maps.newHashMap();
-      for (String name : names) {
-         responses.put(name, ablobstore.removeBlob(containerName, name));
+      for (final String name : names) {
+         responses.put(name, userExecutor.submit(new Callable<Void>() {
+            @Override public Void call() throws Exception {
+               blobstore.removeBlob(containerName, name);
+               return null;
+            }
+         }));
       }
       String message = String.format("deleting directory %s in containerName: %s", directory,
                containerName);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/PutBlobsStrategyImpl.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/PutBlobsStrategyImpl.java b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/PutBlobsStrategyImpl.java
index 6cf457c..7a6cef2 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/PutBlobsStrategyImpl.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/PutBlobsStrategyImpl.java
@@ -20,6 +20,7 @@ import static com.google.common.base.Throwables.propagate;
 import static org.jclouds.concurrent.FutureIterables.awaitCompletion;
 
 import java.util.Map;
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Resource;
@@ -27,7 +28,7 @@ import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.Constants;
-import org.jclouds.blobstore.AsyncBlobStore;
+import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.internal.BlobRuntimeException;
 import org.jclouds.blobstore.reference.BlobStoreConstants;
@@ -42,7 +43,7 @@ import com.google.inject.Inject;
 @Singleton
 public class PutBlobsStrategyImpl implements PutBlobsStrategy {
 
-   private final AsyncBlobStore ablobstore;
+   private final BlobStore blobstore;
    private final ListeningExecutorService userExecutor;
    @Resource
    @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
@@ -56,16 +57,20 @@ public class PutBlobsStrategyImpl implements PutBlobsStrategy {
 
    @Inject
    PutBlobsStrategyImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
-            AsyncBlobStore ablobstore) {
+            BlobStore blobstore) {
       this.userExecutor = userExecutor;
-      this.ablobstore = ablobstore;
+      this.blobstore = blobstore;
    }
 
    @Override
-   public void execute(String containerName, Iterable<? extends Blob> blobs) {
+   public void execute(final String containerName, Iterable<? extends Blob> blobs) {
       Map<Blob, ListenableFuture<?>> responses = Maps.newLinkedHashMap();
-      for (Blob blob : blobs) {
-         responses.put(blob, ablobstore.putBlob(containerName, blob));
+      for (final Blob blob : blobs) {
+         responses.put(blob, userExecutor.submit(new Callable<Object>() {
+            @Override public Object call() throws Exception {
+               return blobstore.putBlob(containerName, blob);
+            }
+         }));
       }
       Map<Blob, Exception> exceptions;
       try {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/main/java/org/jclouds/blobstore/util/BlobStoreUtils.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/util/BlobStoreUtils.java b/blobstore/src/main/java/org/jclouds/blobstore/util/BlobStoreUtils.java
index e9f81ca..c2208cc 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/util/BlobStoreUtils.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/util/BlobStoreUtils.java
@@ -23,18 +23,13 @@ import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.jclouds.blobstore.AsyncBlobStore;
-import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.MutableBlobMetadata;
 import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
-import org.jclouds.blobstore.functions.BlobName;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpRequestFilter;
 import org.jclouds.rest.internal.GeneratedHttpRequest;
 
 import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 
 public class BlobStoreUtils {
    public static <T> HttpRequest cleanRequest(HttpRequest returnVal) {
@@ -45,10 +40,6 @@ public class BlobStoreUtils {
                .headers(returnVal.getHeaders()).payload(returnVal.getPayload()).build();
    }
 
-   public static String parseDirectoryFromPath(String path) {
-      return checkNotNull(path, "path").substring(0, path.lastIndexOf('/'));
-   }
-
    private static Pattern keyFromContainer = Pattern.compile("/?[^/]+/(.*)");
 
    public static String getNameFor(GeneratedHttpRequest request) {
@@ -70,21 +61,6 @@ public class BlobStoreUtils {
       }
       return objectKey;
    }
-
-   private static final BlobName blobName = new BlobName();
-
-   public static ListenableFuture<Void> createParentIfNeededAsync(AsyncBlobStore asyncBlobStore, String container,
-         Blob blob) {
-      checkNotNull(asyncBlobStore, "asyncBlobStore");
-      checkNotNull(container, "container");
-
-      String name = blobName.apply(blob);
-      if (name.indexOf('/') > 0) {
-         return asyncBlobStore.createDirectory(container, parseDirectoryFromPath(name));
-      } else {
-         return Futures.immediateFuture(null);
-      }
-   }
    
    public static MutableBlobMetadata copy(MutableBlobMetadata in) {
       MutableBlobMetadata metadata = new MutableBlobMetadataImpl(in);

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/blobstore/src/test/java/org/jclouds/blobstore/util/BlobStoreUtilsTest.java
----------------------------------------------------------------------
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/util/BlobStoreUtilsTest.java b/blobstore/src/test/java/org/jclouds/blobstore/util/BlobStoreUtilsTest.java
index d412e9d..30b399b 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/util/BlobStoreUtilsTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/util/BlobStoreUtilsTest.java
@@ -16,11 +16,6 @@
  */
 package org.jclouds.blobstore.util;
 
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import static org.jclouds.blobstore.util.BlobStoreUtils.createParentIfNeededAsync;
 import static org.jclouds.blobstore.util.BlobStoreUtils.getNameFor;
 import static org.jclouds.reflect.Reflection2.method;
 import static org.testng.Assert.assertEquals;
@@ -28,83 +23,16 @@ import static org.testng.Assert.assertEquals;
 import java.net.URI;
 import java.util.List;
 
-import org.jclouds.blobstore.AsyncBlobStore;
-import org.jclouds.blobstore.domain.Blob;
-import org.jclouds.blobstore.domain.MutableBlobMetadata;
 import org.jclouds.reflect.Invocation;
 import org.jclouds.rest.internal.GeneratedHttpRequest;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;
-/**
- * Tests behavior of {@code BlobStoreUtils}
- */
+
 @Test(groups = "unit")
 public class BlobStoreUtilsTest {
 
-   public void testCreateParentIfNeededAsyncNoPath() {
-      AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
-      String container = "container";
-      Blob blob = createMock(Blob.class);
-      MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
-
-      expect(blob.getMetadata()).andReturn(md).atLeastOnce();
-      expect(md.getName()).andReturn("hello").atLeastOnce();
-
-      replay(asyncBlobStore);
-      replay(blob);
-      replay(md);
-
-      createParentIfNeededAsync(asyncBlobStore, container, blob);
-
-      verify(asyncBlobStore);
-      verify(blob);
-      verify(md);
-   }
-
-   public void testCreateParentIfNeededAsyncSinglePath() {
-      AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
-      String container = "container";
-      Blob blob = createMock(Blob.class);
-      MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
-
-      expect(blob.getMetadata()).andReturn(md).atLeastOnce();
-      expect(md.getName()).andReturn("rootpath/hello").atLeastOnce();
-      expect(asyncBlobStore.createDirectory("container", "rootpath")).andReturn(null);
-
-      replay(asyncBlobStore);
-      replay(blob);
-      replay(md);
-
-      createParentIfNeededAsync(asyncBlobStore, container, blob);
-
-      verify(asyncBlobStore);
-      verify(blob);
-      verify(md);
-   }
-
-   public void testCreateParentIfNeededAsyncNestedPath() {
-      AsyncBlobStore asyncBlobStore = createMock(AsyncBlobStore.class);
-      String container = "container";
-      Blob blob = createMock(Blob.class);
-      MutableBlobMetadata md = createMock(MutableBlobMetadata.class);
-
-      expect(blob.getMetadata()).andReturn(md).atLeastOnce();
-      expect(md.getName()).andReturn("rootpath/subpath/hello").atLeastOnce();
-      expect(asyncBlobStore.createDirectory("container", "rootpath/subpath")).andReturn(null);
-
-      replay(asyncBlobStore);
-      replay(blob);
-      replay(md);
-
-      createParentIfNeededAsync(asyncBlobStore, container, blob);
-
-      verify(asyncBlobStore);
-      verify(blob);
-      verify(md);
-   }
-
    public void testGetKeyForAzureS3AndRackspace() {
       GeneratedHttpRequest request = requestForEndpointAndArgs(
             "https://jclouds.blob.core.windows.net/adriancole-blobstore0/five",

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
index 865f42c..9545e75 100644
--- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3ClientLiveTest.java
@@ -32,7 +32,6 @@ import java.util.UUID;
 import org.jclouds.aws.AWSResponseException;
 import org.jclouds.aws.domain.Region;
 import org.jclouds.aws.s3.domain.DeleteResult;
-import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.KeyNotFoundException;
 import org.jclouds.blobstore.domain.Blob;
@@ -146,20 +145,6 @@ public class AWSS3ClientLiveTest extends S3ClientLiveTest {
       }
    }
 
-   public void testMultipartAsynchronouslySmallBlob() throws IOException, InterruptedException, Exception {
-      String containerName = getContainerName();
-      
-      try {
-         AsyncBlobStore asyncBlobStore = view.getAsyncBlobStore();
-         asyncBlobStore.createContainerInLocation(null, containerName).get();
-         Blob blob = asyncBlobStore.blobBuilder("small").payload("small").build();
-         asyncBlobStore.putBlob(containerName, blob, PutOptions.Builder.multipart()).get();
-
-      } finally {
-         returnContainer(containerName);
-      }
-   }
-
    public void testPutWithReducedRedundancyStorage() throws InterruptedException {
       String containerName = getContainerName();
       try {

http://git-wip-us.apache.org/repos/asf/jclouds/blob/56a2a8bf/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
----------------------------------------------------------------------
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
index 564adea..f7213d4 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
@@ -16,9 +16,12 @@
  */
 package org.jclouds.hpcloud.objectstorage.blobstore;
 
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+
 import java.util.Set;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
@@ -41,6 +44,7 @@ import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
 import org.jclouds.openstack.swift.blobstore.strategy.internal.MultipartUploadStrategy;
 
 import com.google.common.base.Supplier;
+import com.google.common.util.concurrent.ListeningExecutorService;
 
 @Singleton
 public class HPCloudObjectStorageBlobStore extends SwiftBlobStore {
@@ -48,17 +52,18 @@ public class HPCloudObjectStorageBlobStore extends SwiftBlobStore {
    private EnableCDNAndCache enableCDNAndCache;
 
    @Inject
-   protected HPCloudObjectStorageBlobStore(BlobStoreContext context, BlobUtils blobUtils,
-            Supplier<Location> defaultLocation, @Memoized Supplier<Set<? extends Location>> locations,
-            HPCloudObjectStorageApi sync, ContainerToResourceMetadata container2ResourceMd,
-            BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
-            ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
-            ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
-            Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache,
-            Provider<MultipartUploadStrategy> multipartUploadStrategy) {
-      super(context, blobUtils, defaultLocation, locations, sync, container2ResourceMd, container2ContainerListOptions,
-               container2ResourceList, object2Blob, blob2Object, object2BlobMd, blob2ObjectGetOptions,
-               fetchBlobMetadataProvider, multipartUploadStrategy);
+   protected HPCloudObjectStorageBlobStore(@Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
+         BlobStoreContext context, BlobUtils blobUtils, Supplier<Location> defaultLocation,
+         @Memoized Supplier<Set<? extends Location>> locations, HPCloudObjectStorageApi sync,
+         ContainerToResourceMetadata container2ResourceMd,
+         BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
+         ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
+         ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
+         Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache,
+         Provider<MultipartUploadStrategy> multipartUploadStrategy) {
+      super(userExecutor, context, blobUtils, defaultLocation, locations, sync, container2ResourceMd,
+            container2ContainerListOptions, container2ResourceList, object2Blob, blob2Object, object2BlobMd,
+            blob2ObjectGetOptions, fetchBlobMetadataProvider, multipartUploadStrategy);
       this.enableCDNAndCache = enableCDNAndCache;
 
    }