Repository: jclouds Updated Branches: refs/heads/master 10262df81 -> 1e1eb5a09
Add deleteContainerIfEmpty to BlobStore This matches how most blobstores operate: delete container is a single operation, not a compound operation which recursively deletes blobs. Azure is the only provider which allows deleting a non-empty container. Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/1e1eb5a0 Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/1e1eb5a0 Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/1e1eb5a0 Branch: refs/heads/master Commit: 1e1eb5a092275ddc3cb9de8a8d65ca07d713d27b Parents: 10262df Author: Andrew Gaul <[email protected]> Authored: Tue Jul 22 13:30:03 2014 -0700 Committer: Andrew Gaul <[email protected]> Committed: Fri Jul 25 23:02:39 2014 -0700 ---------------------------------------------------------------------- .../org/jclouds/atmos/AtmosAsyncClient.java | 6 +-- .../atmos/blobstore/AtmosAsyncBlobStore.java | 5 ++- .../fallbacks/TrueOn404FalseOnPathNotEmpty.java | 47 ++++++++++++++++++++ .../org/jclouds/atmos/AtmosAsyncClientTest.java | 7 +-- .../atmos/internal/StubAtmosAsyncClient.java | 14 ++---- .../FilesystemContainerIntegrationTest.java | 24 +++++++--- .../src/main/clojure/org/jclouds/blobstore2.clj | 5 +++ .../org/jclouds/blobstore/AsyncBlobStore.java | 5 +++ .../java/org/jclouds/blobstore/BlobStore.java | 9 ++++ .../jclouds/blobstore/LocalAsyncBlobStore.java | 1 + .../blobstore/internal/BaseAsyncBlobStore.java | 21 +++++++++ .../blobstore/internal/BaseBlobStore.java | 15 +++++++ .../internal/BaseContainerIntegrationTest.java | 30 ++++++++++++- .../blobstore/AzureAsyncBlobStore.java | 9 +++- .../azureblob/blobstore/AzureBlobStore.java | 8 +++- 15 files changed, 180 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/atmos/src/main/java/org/jclouds/atmos/AtmosAsyncClient.java ---------------------------------------------------------------------- diff --git a/apis/atmos/src/main/java/org/jclouds/atmos/AtmosAsyncClient.java b/apis/atmos/src/main/java/org/jclouds/atmos/AtmosAsyncClient.java index 35a3027..5334487 100644 --- a/apis/atmos/src/main/java/org/jclouds/atmos/AtmosAsyncClient.java +++ b/apis/atmos/src/main/java/org/jclouds/atmos/AtmosAsyncClient.java @@ -35,13 +35,13 @@ import javax.ws.rs.core.MediaType; import org.jclouds.Fallbacks.FalseOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.Fallbacks.VoidOnNotFoundOr404; import org.jclouds.atmos.binders.BindMetadataToHeaders; import org.jclouds.atmos.domain.AtmosObject; import org.jclouds.atmos.domain.BoundedSet; import org.jclouds.atmos.domain.DirectoryEntry; import org.jclouds.atmos.domain.SystemMetadata; import org.jclouds.atmos.domain.UserMetadata; +import org.jclouds.atmos.fallbacks.TrueOn404FalseOnPathNotEmpty; import org.jclouds.atmos.filters.SignRequest; import org.jclouds.atmos.functions.AtmosObjectName; import org.jclouds.atmos.functions.ParseDirectoryListFromContentAndHeaders; @@ -201,10 +201,10 @@ public interface AtmosAsyncClient extends Closeable { */ @Named("DeleteObject") @DELETE - @Fallback(VoidOnNotFoundOr404.class) + @Fallback(TrueOn404FalseOnPathNotEmpty.class) @Path("/{path}") @Consumes(MediaType.WILDCARD) - ListenableFuture<Void> deletePath(@PathParam("path") String path); + ListenableFuture<Boolean> deletePath(@PathParam("path") String path); /** * @see AtmosClient#pathExists http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosAsyncBlobStore.java ---------------------------------------------------------------------- diff --git a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosAsyncBlobStore.java b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosAsyncBlobStore.java index 7a98a3d..983f068 100644 --- a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosAsyncBlobStore.java +++ b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosAsyncBlobStore.java @@ -59,9 +59,11 @@ import org.jclouds.domain.Location; import org.jclouds.http.options.GetOptions; import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -260,7 +262,8 @@ public class AtmosAsyncBlobStore extends BaseAsyncBlobStore { */ @Override public ListenableFuture<Void> removeBlob(String container, String key) { - return async.deletePath(container + "/" + key); + return Futures.transform(async.deletePath(container + "/" + key), Functions.constant((Void) null), + userExecutor); } @Override http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/atmos/src/main/java/org/jclouds/atmos/fallbacks/TrueOn404FalseOnPathNotEmpty.java ---------------------------------------------------------------------- diff --git a/apis/atmos/src/main/java/org/jclouds/atmos/fallbacks/TrueOn404FalseOnPathNotEmpty.java b/apis/atmos/src/main/java/org/jclouds/atmos/fallbacks/TrueOn404FalseOnPathNotEmpty.java new file mode 100644 index 0000000..18dda1e --- /dev/null +++ b/apis/atmos/src/main/java/org/jclouds/atmos/fallbacks/TrueOn404FalseOnPathNotEmpty.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.atmos.fallbacks; + +import static com.google.common.base.Throwables.propagate; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +import org.jclouds.Fallback; +import org.jclouds.atmos.AtmosResponseException; +import org.jclouds.atmos.reference.AtmosErrorCode; +import org.jclouds.http.HttpUtils; + +import com.google.common.util.concurrent.ListenableFuture; + +public final class TrueOn404FalseOnPathNotEmpty implements Fallback<Boolean> { + @Override + public ListenableFuture<Boolean> create(Throwable t) throws Exception { + return immediateFuture(createOrPropagate(t)); + } + + @Override + public Boolean createOrPropagate(Throwable t) throws Exception { + if (HttpUtils.contains404(t)) { + return true; + } + AtmosResponseException exception = getFirstThrowableOfType(t, AtmosResponseException.class); + if (exception != null && exception.getError().getCode() == AtmosErrorCode.DIRECTORY_NOT_EMPTY.getCode()) { + return false; + } + throw propagate(t); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/atmos/src/test/java/org/jclouds/atmos/AtmosAsyncClientTest.java ---------------------------------------------------------------------- diff --git a/apis/atmos/src/test/java/org/jclouds/atmos/AtmosAsyncClientTest.java b/apis/atmos/src/test/java/org/jclouds/atmos/AtmosAsyncClientTest.java index 2592a05..7dc2297 100644 --- a/apis/atmos/src/test/java/org/jclouds/atmos/AtmosAsyncClientTest.java +++ b/apis/atmos/src/test/java/org/jclouds/atmos/AtmosAsyncClientTest.java @@ -23,11 +23,11 @@ import java.io.IOException; import org.jclouds.Fallbacks.FalseOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; -import org.jclouds.Fallbacks.VoidOnNotFoundOr404; import org.jclouds.apis.ApiMetadata; import org.jclouds.atmos.blobstore.functions.BlobToObject; import org.jclouds.atmos.config.AtmosRestClientModule; import org.jclouds.atmos.domain.AtmosObject; +import org.jclouds.atmos.fallbacks.TrueOn404FalseOnPathNotEmpty; import org.jclouds.atmos.filters.SignRequest; import org.jclouds.atmos.functions.ParseDirectoryListFromContentAndHeaders; import org.jclouds.atmos.functions.ParseNullableURIFromListOrLocationHeaderIf20x; @@ -44,6 +44,7 @@ import org.jclouds.date.TimeStamp; import org.jclouds.http.HttpRequest; import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x; import org.jclouds.http.functions.ReleasePayloadAndReturn; +import org.jclouds.http.functions.ReturnTrueIf2xx; import org.jclouds.http.options.GetOptions; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.internal.BaseAsyncClientTest; @@ -264,9 +265,9 @@ public class AtmosAsyncClientTest extends BaseAsyncClientTest<AtmosAsyncClient> assertNonPayloadHeadersEqual(request, HttpHeaders.ACCEPT + ": */*\n"); assertPayloadEquals(request, null, null, false); - assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class); + assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class); assertSaxResponseParserClassEquals(method, null); - assertFallbackClassEquals(method, VoidOnNotFoundOr404.class); + assertFallbackClassEquals(method, TrueOn404FalseOnPathNotEmpty.class); checkFilters(request); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/atmos/src/test/java/org/jclouds/atmos/internal/StubAtmosAsyncClient.java ---------------------------------------------------------------------- diff --git a/apis/atmos/src/test/java/org/jclouds/atmos/internal/StubAtmosAsyncClient.java b/apis/atmos/src/test/java/org/jclouds/atmos/internal/StubAtmosAsyncClient.java index bb56596..211d0a4 100644 --- a/apis/atmos/src/test/java/org/jclouds/atmos/internal/StubAtmosAsyncClient.java +++ b/apis/atmos/src/test/java/org/jclouds/atmos/internal/StubAtmosAsyncClient.java @@ -49,6 +49,7 @@ import org.jclouds.http.options.GetOptions; import org.jclouds.lifecycle.Closer; import com.google.common.base.Function; +import com.google.common.base.Functions; import com.google.common.base.Throwables; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -134,21 +135,14 @@ public class StubAtmosAsyncClient implements AtmosAsyncClient { } @Override - public ListenableFuture<Void> deletePath(String path) { + public ListenableFuture<Boolean> deletePath(String path) { if (path.indexOf('/') == path.length() - 1) { // chop off the trailing slash - return Futures.transform(blobStore.deleteContainerIfEmpty(path.substring(0, path.length() - 1)), - new Function<Boolean, Void>() { - - public Void apply(Boolean from) { - return null; - } - - }, userExecutor); + return blobStore.deleteContainerIfEmpty(path.substring(0, path.length() - 1)); } else { String container = path.substring(0, path.indexOf('/')); path = path.substring(path.indexOf('/') + 1); - return blobStore.removeBlob(container, path); + return Futures.transform(blobStore.removeBlob(container, path), Functions.constant(Boolean.TRUE), userExecutor); } } http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java ---------------------------------------------------------------------- diff --git a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java index 39ae537..f495479 100644 --- a/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java +++ b/apis/filesystem/src/test/java/org/jclouds/filesystem/integration/FilesystemContainerIntegrationTest.java @@ -101,6 +101,24 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration @Override @Test(dataProvider = "ignoreOnWindows") + public void deleteContainerWithoutContents() throws InterruptedException { + super.deleteContainerWithoutContents(); + } + + @Override + @Test(dataProvider = "ignoreOnWindows") + public void deleteContainerIfEmptyWithContents() throws InterruptedException { + super.deleteContainerIfEmptyWithContents(); + } + + @Override + @Test(dataProvider = "ignoreOnWindows") + public void deleteContainerIfEmptyWithoutContents() throws InterruptedException { + super.deleteContainerIfEmptyWithoutContents(); + } + + @Override + @Test(dataProvider = "ignoreOnWindows") public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException { super.testListContainer(); } @@ -131,12 +149,6 @@ public class FilesystemContainerIntegrationTest extends BaseContainerIntegration @Override @Test(dataProvider = "ignoreOnWindows") - public void deleteContainerIfEmpty() throws InterruptedException { - super.deleteContainerIfEmpty(); - } - - @Override - @Test(dataProvider = "ignoreOnWindows") public void testListContainerMaxResults() throws InterruptedException { super.testListContainerMaxResults(); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/blobstore/src/main/clojure/org/jclouds/blobstore2.clj ---------------------------------------------------------------------- diff --git a/blobstore/src/main/clojure/org/jclouds/blobstore2.clj b/blobstore/src/main/clojure/org/jclouds/blobstore2.clj index 6eb57d5..8b18636 100644 --- a/blobstore/src/main/clojure/org/jclouds/blobstore2.clj +++ b/blobstore/src/main/clojure/org/jclouds/blobstore2.clj @@ -207,6 +207,11 @@ Options can also be specified for extension modules [^BlobStore blobstore container-name] (.deleteContainer blobstore container-name)) +(defn delete-container-if-empty + "Delete a container if empty." + [^BlobStore blobstore container-name] + (.deleteContainerIfEmpty blobstore container-name)) + (defn container-exists? "Predicate to check presence of a container" [^BlobStore blobstore container-name] http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/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 5b4609d..22feebd 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/AsyncBlobStore.java @@ -103,6 +103,11 @@ public interface AsyncBlobStore { ListenableFuture<Void> deleteContainer(String container); /** + * @see BlobStore#deleteContainerIfEmpty + */ + ListenableFuture<Boolean> deleteContainerIfEmpty(String container); + + /** * @see BlobStore#directoryExists */ ListenableFuture<Boolean> directoryExists(String container, String directory); http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java ---------------------------------------------------------------------- diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java index eab9ae6..88db39a 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java @@ -140,10 +140,19 @@ public interface BlobStore { * * @param container * what to delete + * @param container name of the container to delete */ void deleteContainer(String container); /** + * Deletes a container if it is empty. + * + * @param container name of the container to delete + * @return true if the container was deleted or does not exist + */ + boolean deleteContainerIfEmpty(String container); + + /** * Determines if a directory exists * * @param container http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/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 index a411e21..59a3f26 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/LocalAsyncBlobStore.java @@ -256,6 +256,7 @@ public class LocalAsyncBlobStore extends BaseAsyncBlobStore { return immediateFuture(null); } + @Override public ListenableFuture<Boolean> deleteContainerIfEmpty(final String container) { Boolean returnVal = true; if (storageStrategy.containerExists(container)) { http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/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 index 36e5ff5..8bddf7f 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java @@ -266,6 +266,21 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore { }); } + @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) { @@ -284,6 +299,12 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore { 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/1e1eb5a0/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java ---------------------------------------------------------------------- diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java index 1ef8553..fe08c8a 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java @@ -189,6 +189,15 @@ public abstract class BaseBlobStore implements BlobStore { deletePathAndEnsureGone(container); } + @Override + public boolean deleteContainerIfEmpty(String container) { + try { + return deleteAndVerifyContainerGone(container); + } catch (ContainerNotFoundException cnfe) { + return true; + } + } + protected void deletePathAndEnsureGone(String path) { checkState(retry(new Predicate<String>() { public boolean apply(String in) { @@ -207,6 +216,12 @@ public abstract class BaseBlobStore implements BlobStore { return locations.get(); } + /** + * Delete a container if it is empty. + * + * @param container what to delete + * @return whether container was deleted + */ protected abstract boolean deleteAndVerifyContainerGone(String container); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseContainerIntegrationTest.java ---------------------------------------------------------------------- diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseContainerIntegrationTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseContainerIntegrationTest.java index d97f26e..c3bdbb9 100644 --- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseContainerIntegrationTest.java +++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseContainerIntegrationTest.java @@ -24,6 +24,8 @@ import static org.jclouds.blobstore.options.ListContainerOptions.Builder.afterMa import static org.jclouds.blobstore.options.ListContainerOptions.Builder.inDirectory; import static org.jclouds.blobstore.options.ListContainerOptions.Builder.maxResults; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; import java.io.IOException; import java.util.Set; @@ -280,7 +282,7 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest { } @Test(groups = { "integration", "live" }) - public void deleteContainerIfEmpty() throws InterruptedException { + public void deleteContainerWithoutContents() throws InterruptedException { final String containerName = getContainerName(); try { view.getBlobStore().deleteContainer(containerName); @@ -292,6 +294,32 @@ public class BaseContainerIntegrationTest extends BaseBlobStoreIntegrationTest { } @Test(groups = { "integration", "live" }) + public void deleteContainerIfEmptyWithContents() throws InterruptedException { + String containerName = getContainerName(); + try { + addBlobToContainer(containerName, "test"); + assertFalse(view.getBlobStore().deleteContainerIfEmpty(containerName)); + assertTrue(view.getBlobStore().containerExists(containerName)); + } finally { + recycleContainerAndAddToPool(containerName); + } + } + + @Test(groups = { "integration", "live" }) + public void deleteContainerIfEmptyWithoutContents() throws InterruptedException { + final String containerName = getContainerName(); + try { + assertTrue(view.getBlobStore().deleteContainerIfEmpty(containerName)); + assertNotExists(containerName); + // verify that false is returned even if the container does not exist + assertTrue(view.getBlobStore().deleteContainerIfEmpty(containerName)); + } finally { + // this container is now deleted, so we can't reuse it directly + recycleContainerAndAddToPool(containerName); + } + } + + @Test(groups = { "integration", "live" }) public void testListContainer() throws InterruptedException, ExecutionException, TimeoutException { String containerName = getContainerName(); try { http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java ---------------------------------------------------------------------- diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java index d1ba11e..a0bba9f 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureAsyncBlobStore.java @@ -64,6 +64,7 @@ import org.jclouds.http.options.GetOptions; import com.google.common.base.Function; import com.google.common.base.Supplier; 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; import org.jclouds.io.Payload; @@ -278,7 +279,13 @@ public class AzureAsyncBlobStore extends BaseAsyncBlobStore { @Override protected boolean deleteAndVerifyContainerGone(String container) { - throw new UnsupportedOperationException("please use deleteContainer"); + // Azure deleteContainer supports deleting empty containers so emulate + // deleteIfEmpty by listing. + if (!Futures.getUnchecked(list(container)).isEmpty()) { + return false; + } + Futures.getUnchecked(async.deleteContainer(container)); + return true; } @Override http://git-wip-us.apache.org/repos/asf/jclouds/blob/1e1eb5a0/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java ---------------------------------------------------------------------- diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java index c4d4c8a..15a3f8b 100644 --- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java +++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java @@ -266,7 +266,13 @@ public class AzureBlobStore extends BaseBlobStore { @Override protected boolean deleteAndVerifyContainerGone(String container) { - throw new UnsupportedOperationException("please use deleteContainer"); + // Azure deleteContainer supports deleting empty containers so emulate + // deleteIfEmpty by listing. + if (!list(container).isEmpty()) { + return false; + } + sync.deleteContainer(container); + return true; } @Override
