You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2014/07/26 08:05:38 UTC
git commit: Add deleteContainerIfEmpty to BlobStore
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 <ga...@apache.org>
Authored: Tue Jul 22 13:30:03 2014 -0700
Committer: Andrew Gaul <ga...@apache.org>
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