curator-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From randg...@apache.org
Subject git commit: Added ability to recursively delete a hierarchy. Zookeeper already provides this in their ZKUtil.java package
Date Thu, 11 Jul 2013 17:39:34 GMT
Updated Branches:
  refs/heads/0v [created] c8942b130
  refs/heads/CURATOR-30 [created] 5f043d47b


Added ability to recursively delete a hierarchy. Zookeeper already provides this in their
ZKUtil.java package


Project: http://git-wip-us.apache.org/repos/asf/incubator-curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-curator/commit/5f043d47
Tree: http://git-wip-us.apache.org/repos/asf/incubator-curator/tree/5f043d47
Diff: http://git-wip-us.apache.org/repos/asf/incubator-curator/diff/5f043d47

Branch: refs/heads/CURATOR-30
Commit: 5f043d47b7fe2749cf8b0d91309d7088032a56f3
Parents: c8942b1
Author: randgalt <randgalt@apache.org>
Authored: Wed Jul 10 12:06:01 2013 -0700
Committer: randgalt <randgalt@apache.org>
Committed: Wed Jul 10 12:06:01 2013 -0700

----------------------------------------------------------------------
 .../java/org/apache/curator/utils/ZKPaths.java  |  57 ++++++++--
 .../framework/api/BackgroundVersionable.java    |  25 +++++
 .../framework/api/ChildrenDeletable.java        |  30 ++++++
 .../curator/framework/api/DeleteBuilder.java    |  21 +---
 .../framework/api/DeleteBuilderBase.java        |  25 -----
 .../curator/framework/api/Guaranteeable.java    |  40 +++++++
 .../framework/imps/DeleteBuilderImpl.java       | 105 ++++++++++++++-----
 .../curator/framework/imps/TestFramework.java   |  79 ++++++++++++--
 8 files changed, 292 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
----------------------------------------------------------------------
diff --git a/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java b/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
index 40c5bd7..4a62d86 100644
--- a/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
+++ b/curator-client/src/main/java/org/apache/curator/utils/ZKPaths.java
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.curator.utils;
 
 import com.google.common.collect.Lists;
@@ -33,10 +34,10 @@ public class ZKPaths
      * Apply the namespace to the given path
      *
      * @param namespace namespace (can be null)
-     * @param path path
+     * @param path      path
      * @return adjusted path
      */
-    public static String    fixForNamespace(String namespace, String path)
+    public static String fixForNamespace(String namespace, String path)
     {
         if ( namespace != null )
         {
@@ -47,7 +48,7 @@ public class ZKPaths
 
     /**
      * Given a full path, return the node name. i.e. "/one/two/three" will return "three"
-     * 
+     *
      * @param path the path
      * @return the node
      */
@@ -59,7 +60,7 @@ public class ZKPaths
         {
             return path;
         }
-        if ( (i + 1) >= path.length()  )
+        if ( (i + 1) >= path.length() )
         {
             return "";
         }
@@ -68,8 +69,8 @@ public class ZKPaths
 
     public static class PathAndNode
     {
-        private final String        path;
-        private final String        node;
+        private final String path;
+        private final String node;
 
         public PathAndNode(String path, String node)
         {
@@ -102,7 +103,7 @@ public class ZKPaths
         {
             return new PathAndNode(path, "");
         }
-        if ( (i + 1) >= path.length()  )
+        if ( (i + 1) >= path.length() )
         {
             return new PathAndNode("/", "");
         }
@@ -131,8 +132,8 @@ public class ZKPaths
      * Make sure all the nodes in the path are created. NOTE: Unlike File.mkdirs(), Zookeeper
doesn't distinguish
      * between directories and files. So, every node in the path is created. The data for
each node is an empty blob
      *
-     * @param zookeeper the client
-     * @param path      path to ensure
+     * @param zookeeper    the client
+     * @param path         path to ensure
      * @param makeLastNode if true, all nodes are created. If false, only the parent nodes
are created
      * @throws InterruptedException thread interruption
      * @throws org.apache.zookeeper.KeeperException
@@ -178,6 +179,44 @@ public class ZKPaths
     }
 
     /**
+     * Recursively deletes children of a node.
+     *
+     * @param zookeeper  the client
+     * @param path       path of the node to delete
+     * @param deleteSelf flag that indicates that the node should also get deleted
+     * @throws InterruptedException
+     * @throws KeeperException
+     */
+    public static void deleteChildren(ZooKeeper zookeeper, String path, boolean deleteSelf)
throws InterruptedException, KeeperException
+    {
+        PathUtils.validatePath(path);
+
+        List<String> children = zookeeper.getChildren(path, false);
+        for ( String child : children )
+        {
+            String fullPath = makePath(path, child);
+            deleteChildren(zookeeper, fullPath, true);
+        }
+
+        if ( deleteSelf )
+        {
+            try
+            {
+                zookeeper.delete(path, -1);
+            }
+            catch ( KeeperException.NotEmptyException e )
+            {
+                //someone has created a new child since we checked ... delete again.
+                deleteChildren(zookeeper, path, deleteSelf);
+            }
+            catch ( KeeperException.NoNodeException e )
+            {
+                // ignore... someone else has deleted the node it since we checked
+            }
+        }
+    }
+
+    /**
      * Return the children of the given path sorted by sequence number
      *
      * @param zookeeper the client

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundVersionable.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundVersionable.java
b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundVersionable.java
new file mode 100644
index 0000000..bd68788
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundVersionable.java
@@ -0,0 +1,25 @@
+/**
+ * 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.apache.curator.framework.api;
+
+public interface BackgroundVersionable extends
+    BackgroundPathable<Void>,
+    Versionable<BackgroundPathable<Void>>
+{
+}

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/api/ChildrenDeletable.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/ChildrenDeletable.java
b/curator-framework/src/main/java/org/apache/curator/framework/api/ChildrenDeletable.java
new file mode 100644
index 0000000..d568be3
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ChildrenDeletable.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.curator.framework.api;
+
+public interface ChildrenDeletable extends BackgroundVersionable
+{
+    /**
+     * <p>
+     *     Will also delete children if they exist.
+     * </p>
+     * @return this
+     */
+    public BackgroundVersionable deletingChildrenIfNeeded();
+}

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilder.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilder.java
b/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilder.java
index d0b7755..3a3faf7 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilder.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilder.java
@@ -18,25 +18,6 @@
  */
 package org.apache.curator.framework.api;
 
-import org.apache.curator.framework.CuratorFramework;
-
-public interface DeleteBuilder extends DeleteBuilderBase
+public interface DeleteBuilder extends Guaranteeable, ChildrenDeletable
 {
-    /**
-     * <p>
-     *     Solves this edge case: deleting a node can fail due to connection issues. Further,
-     *     if the node was ephemeral, the node will not get auto-deleted as the session is
still valid.
-     *     This can wreak havoc with lock implementations.
-     * </p>
-     * 
-     * <p>
-     *     When <code>guaranteed</code> is set, Curator will record failed node
deletions and 
-     *     attempt to delete them in the background until successful. NOTE: you will still
get an
-     *     exception when the deletion fails. But, you can be assured that as long as the

-     *     {@link CuratorFramework} instance is open attempts will be made to delete the
node.
-     * </p>
-     *  
-     * @return this
-     */
-    public DeleteBuilderBase    guaranteed();
 }

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilderBase.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilderBase.java
b/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilderBase.java
deleted file mode 100644
index 469e339..0000000
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/DeleteBuilderBase.java
+++ /dev/null
@@ -1,25 +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.apache.curator.framework.api;
-
-public interface DeleteBuilderBase extends
-    BackgroundPathable<Void>,
-    Versionable<BackgroundPathable<Void>>
-{
-}

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/api/Guaranteeable.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Guaranteeable.java
b/curator-framework/src/main/java/org/apache/curator/framework/api/Guaranteeable.java
new file mode 100644
index 0000000..481911b
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Guaranteeable.java
@@ -0,0 +1,40 @@
+/**
+ * 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.apache.curator.framework.api;
+
+public interface Guaranteeable extends BackgroundVersionable
+{
+    /**
+     * <p>
+     *     Solves this edge case: deleting a node can fail due to connection issues. Further,
+     *     if the node was ephemeral, the node will not get auto-deleted as the session is
still valid.
+     *     This can wreak havoc with lock implementations.
+     * </p>
+     *
+     * <p>
+     *     When <code>guaranteed</code> is set, Curator will record failed node
deletions and
+     *     attempt to delete them in the background until successful. NOTE: you will still
get an
+     *     exception when the deletion fails. But, you can be assured that as long as the
+     *     {@link org.apache.curator.framework.CuratorFramework} instance is open attempts
will be made to delete the node.
+     * </p>
+     *  
+     * @return this
+     */
+    public ChildrenDeletable guaranteed();
+}

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
index 86dcc40..1768cc9 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java
@@ -16,20 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.curator.framework.imps;
 
 import org.apache.curator.RetryLoop;
 import org.apache.curator.TimeTrace;
 import org.apache.curator.framework.api.BackgroundCallback;
 import org.apache.curator.framework.api.BackgroundPathable;
+import org.apache.curator.framework.api.BackgroundVersionable;
+import org.apache.curator.framework.api.ChildrenDeletable;
 import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.framework.api.CuratorEventType;
 import org.apache.curator.framework.api.DeleteBuilder;
-import org.apache.curator.framework.api.DeleteBuilderBase;
 import org.apache.curator.framework.api.Pathable;
 import org.apache.curator.framework.api.transaction.CuratorTransactionBridge;
 import org.apache.curator.framework.api.transaction.OperationType;
 import org.apache.curator.framework.api.transaction.TransactionDeleteBuilder;
+import org.apache.curator.utils.ZKPaths;
 import org.apache.zookeeper.AsyncCallback;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Op;
@@ -38,27 +41,29 @@ import java.util.concurrent.Executor;
 
 class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>
 {
-    private final CuratorFrameworkImpl  client;
-    private int                         version;
-    private Backgrounding               backgrounding;
-    private boolean                     guaranteed;
+    private final CuratorFrameworkImpl client;
+    private int version;
+    private Backgrounding backgrounding;
+    private boolean deletingChildrenIfNeeded;
+    private boolean guaranteed;
 
     DeleteBuilderImpl(CuratorFrameworkImpl client)
     {
         this.client = client;
         version = -1;
         backgrounding = new Backgrounding();
+        deletingChildrenIfNeeded = false;
         guaranteed = false;
     }
 
-    TransactionDeleteBuilder    asTransactionDeleteBuilder(final CuratorTransactionImpl curatorTransaction,
final CuratorMultiTransactionRecord transaction)
+    TransactionDeleteBuilder asTransactionDeleteBuilder(final CuratorTransactionImpl curatorTransaction,
final CuratorMultiTransactionRecord transaction)
     {
         return new TransactionDeleteBuilder()
         {
             @Override
             public CuratorTransactionBridge forPath(String path) throws Exception
             {
-                String      fixedPath = client.fixForNamespace(path);
+                String fixedPath = client.fixForNamespace(path);
                 transaction.add(Op.delete(fixedPath, version), OperationType.DELETE, path);
                 return curatorTransaction;
             }
@@ -73,13 +78,20 @@ class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>
     }
 
     @Override
-    public DeleteBuilderBase guaranteed()
+    public ChildrenDeletable guaranteed()
     {
         guaranteed = true;
         return this;
     }
 
     @Override
+    public BackgroundVersionable deletingChildrenIfNeeded()
+    {
+        deletingChildrenIfNeeded = true;
+        return this;
+    }
+
+    @Override
     public BackgroundPathable<Void> withVersion(int version)
     {
         this.version = version;
@@ -131,34 +143,63 @@ class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>
     @Override
     public void performBackgroundOperation(final OperationAndData<String> operationAndData)
throws Exception
     {
-        final TimeTrace   trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Background");
+        final TimeTrace trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Background");
         client.getZooKeeper().delete
-        (
-            operationAndData.getData(),
-            version,
-            new AsyncCallback.VoidCallback()
+            (
+                operationAndData.getData(),
+                version,
+                new AsyncCallback.VoidCallback()
+                {
+                    @Override
+                    public void processResult(int rc, String path, Object ctx)
+                    {
+                        trace.commit();
+                        if ( (rc == KeeperException.Code.NOTEMPTY.intValue()) &&
deletingChildrenIfNeeded )
+                        {
+                            backgroundDeleteChildrenThenNode(operationAndData);
+                        }
+                        else
+                        {
+                            CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.DELETE,
rc, path, null, ctx, null, null, null, null, null);
+                            client.processBackgroundOperation(operationAndData, event);
+                        }
+                    }
+                },
+                backgrounding.getContext()
+            );
+    }
+
+    private void backgroundDeleteChildrenThenNode(final OperationAndData<String> mainOperationAndData)
+    {
+        BackgroundOperation<String> operation = new BackgroundOperation<String>()
+        {
+            @Override
+            public void performBackgroundOperation(OperationAndData<String> dummy)
throws Exception
             {
-                @Override
-                public void processResult(int rc, String path, Object ctx)
+                try
+                {
+                    ZKPaths.deleteChildren(client.getZooKeeper(), mainOperationAndData.getData(),
false);
+                }
+                catch ( KeeperException e )
                 {
-                    trace.commit();
-                    CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.DELETE,
rc, path, null, ctx, null, null, null, null, null);
-                    client.processBackgroundOperation(operationAndData, event);
+                    // ignore
                 }
-            },
-            backgrounding.getContext()
-        );
+                client.queueOperation(mainOperationAndData);
+            }
+        };
+        OperationAndData<String> parentOperation = new OperationAndData<String>(operation,
mainOperationAndData.getData(), null, null);
+        client.queueOperation(parentOperation);
     }
 
     @Override
     public Void forPath(String path) throws Exception
     {
-        final String        unfixedPath = path;
+        final String unfixedPath = path;
         path = client.fixForNamespace(path);
 
         if ( backgrounding.inBackground() )
         {
-            OperationAndData.ErrorCallback<String>  errorCallback = null;
+            OperationAndData.ErrorCallback<String> errorCallback = null;
             if ( guaranteed )
             {
                 errorCallback = new OperationAndData.ErrorCallback<String>()
@@ -186,7 +227,7 @@ class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>
 
     private void pathInForeground(final String path, String unfixedPath) throws Exception
     {
-        TimeTrace       trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Foreground");
+        TimeTrace trace = client.getZookeeperClient().startTracer("DeleteBuilderImpl-Foreground");
         try
         {
             RetryLoop.callWithRetry
@@ -197,7 +238,21 @@ class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>
                     @Override
                     public Void call() throws Exception
                     {
-                        client.getZooKeeper().delete(path, version);
+                        try
+                        {
+                            client.getZooKeeper().delete(path, version);
+                        }
+                        catch ( KeeperException.NotEmptyException e )
+                        {
+                            if ( deletingChildrenIfNeeded )
+                            {
+                                ZKPaths.deleteChildren(client.getZooKeeper(), path, true);
+                            }
+                            else
+                            {
+                                throw e;
+                            }
+                        }
                         return null;
                     }
                 }

http://git-wip-us.apache.org/repos/asf/incubator-curator/blob/5f043d47/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
index f7ef6e9..d974279 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFramework.java
@@ -398,25 +398,25 @@ public class TestFramework extends BaseClassForTests
         try
         {
             client.getCuratorListenable().addListener
-            (
-                new CuratorListener()
-                {
-                    @Override
-                    public void eventReceived(CuratorFramework client, CuratorEvent event)
throws Exception
+                (
+                    new CuratorListener()
                     {
-                        if ( event.getType() == CuratorEventType.SYNC )
+                        @Override
+                        public void eventReceived(CuratorFramework client, CuratorEvent event)
throws Exception
                         {
-                            Assert.assertEquals(event.getPath(), "/head");
-                            ((CountDownLatch)event.getContext()).countDown();
+                            if ( event.getType() == CuratorEventType.SYNC )
+                            {
+                                Assert.assertEquals(event.getPath(), "/head");
+                                ((CountDownLatch)event.getContext()).countDown();
+                            }
                         }
                     }
-                }
-            );
+                );
 
             client.create().forPath("/head");
             Assert.assertNotNull(client.checkExists().forPath("/head"));
 
-            CountDownLatch      latch = new CountDownLatch(1);
+            CountDownLatch latch = new CountDownLatch(1);
             client.sync("/head", latch);
             Assert.assertTrue(latch.await(10, TimeUnit.SECONDS));
         }
@@ -495,6 +495,43 @@ public class TestFramework extends BaseClassForTests
     }
 
     @Test
+    public void     testBackgroundDeleteWithChildren() throws Exception
+    {
+        CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(),
new RetryOneTime(1));
+        client.start();
+        try
+        {
+            client.getCuratorListenable().addListener
+            (
+                    new CuratorListener()
+                    {
+                        @Override
+                        public void eventReceived(CuratorFramework client, CuratorEvent event)
throws Exception
+                        {
+                            if ( event.getType() == CuratorEventType.DELETE )
+                            {
+                                Assert.assertEquals(event.getPath(), "/one/two");
+                                ((CountDownLatch)event.getContext()).countDown();
+                            }
+                        }
+                    }
+            );
+
+            client.create().creatingParentsIfNeeded().forPath("/one/two/three/four");
+            Assert.assertNotNull(client.checkExists().forPath("/one/two/three/four"));
+
+            CountDownLatch      latch = new CountDownLatch(1);
+            client.delete().deletingChildrenIfNeeded().inBackground(latch).forPath("/one/two");
+            Assert.assertTrue(latch.await(10, TimeUnit.SECONDS));
+            Assert.assertNull(client.checkExists().forPath("/one/two"));
+        }
+        finally
+        {
+            client.close();
+        }
+    }
+
+    @Test
     public void     testDelete() throws Exception
     {
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(),
new RetryOneTime(1));
@@ -513,6 +550,26 @@ public class TestFramework extends BaseClassForTests
     }
 
     @Test
+    public void testDeleteWithChildren() throws Exception
+    {
+        CuratorFrameworkFactory.Builder      builder = CuratorFrameworkFactory.builder();
+        CuratorFramework client = builder.connectString(server.getConnectString()).retryPolicy(new
RetryOneTime(1)).build();
+        client.start();
+        try
+        {
+            client.create().creatingParentsIfNeeded().forPath("/one/two/three/four/five/six",
"foo".getBytes());
+            client.delete().deletingChildrenIfNeeded().forPath("/one/two/three/four/five");
+            Assert.assertNull(client.checkExists().forPath("/one/two/three/four/five"));
+            client.delete().deletingChildrenIfNeeded().forPath("/one/two");
+            Assert.assertNull(client.checkExists().forPath("/one/two"));
+        }
+        finally
+        {
+            client.close();
+        }
+    }
+
+    @Test
     public void     testGetSequentialChildren() throws Exception
     {
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(),
new RetryOneTime(1));


Mime
View raw message