This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/curator.git


The following commit(s) were added to refs/heads/master by this push:
     new d1b64d63 CURATOR-665: Convey mkdirs exception to create backgorund 
(#453)
d1b64d63 is described below

commit d1b64d63d9772495e22154260b1c2634432cd436
Author: tison <[email protected]>
AuthorDate: Mon Apr 3 16:22:39 2023 +0800

    CURATOR-665: Convey mkdirs exception to create backgorund (#453)
    
    Signed-off-by: tison <[email protected]>
---
 .../java/org/apache/curator/utils/ZKPaths.java     |  8 +--
 .../curator/framework/imps/CreateBuilderImpl.java  | 40 ++++++++---
 .../x/async/modeled/TestModeledFramework.java      | 78 ++++++++++++++++++++--
 3 files changed, 107 insertions(+), 19 deletions(-)

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 0e762573..9ac88e16 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
@@ -21,6 +21,8 @@ package org.apache.curator.utils;
 
 import com.google.common.base.Splitter;
 import com.google.common.collect.Lists;
+import java.util.Collections;
+import java.util.List;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.ZooDefs;
@@ -28,8 +30,6 @@ import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.data.ACL;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.Collections;
-import java.util.List;
 
 public class ZKPaths
 {
@@ -228,7 +228,7 @@ public class ZKPaths
     /**
      * Extracts the ten-digit suffix from a sequential znode path. Does not 
currently perform validation on the
      * provided path; it will just return a string comprising the last ten 
characters.
-     * 
+     *
      * @param path the path of a sequential znodes
      * @return the sequential suffix
      */
@@ -350,7 +350,7 @@ public class ZKPaths
                     }
                     zookeeper.create(subPath, new byte[0], acl, 
getCreateMode(asContainers));
                 }
-                catch ( KeeperException.NodeExistsException e )
+                catch (KeeperException.NodeExistsException ignore)
                 {
                     // ignore... someone else has created it since we checked
                 }
diff --git 
a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
 
b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
index adca0160..6b52e662 100644
--- 
a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
+++ 
b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
@@ -22,9 +22,32 @@ package org.apache.curator.framework.imps;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.curator.RetryLoop;
 import org.apache.curator.drivers.OperationTrace;
-import org.apache.curator.framework.api.*;
+import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
+import 
org.apache.curator.framework.api.ACLCreateModeBackgroundPathAndBytesable;
+import org.apache.curator.framework.api.ACLCreateModePathAndBytesable;
+import 
org.apache.curator.framework.api.ACLCreateModeStatBackgroundPathAndBytesable;
+import org.apache.curator.framework.api.ACLPathAndBytesable;
+import org.apache.curator.framework.api.BackgroundCallback;
+import org.apache.curator.framework.api.BackgroundPathAndBytesable;
+import org.apache.curator.framework.api.CreateBackgroundModeACLable;
+import org.apache.curator.framework.api.CreateBackgroundModeStatACLable;
+import org.apache.curator.framework.api.CreateBuilder;
+import org.apache.curator.framework.api.CreateBuilder2;
+import org.apache.curator.framework.api.CreateBuilderMain;
+import 
org.apache.curator.framework.api.CreateProtectACLCreateModePathAndBytesable;
+import org.apache.curator.framework.api.CuratorEvent;
+import org.apache.curator.framework.api.CuratorEventType;
+import org.apache.curator.framework.api.ErrorListenerPathAndBytesable;
+import org.apache.curator.framework.api.PathAndBytesable;
+import org.apache.curator.framework.api.ProtectACLCreateModePathAndBytesable;
+import 
org.apache.curator.framework.api.ProtectACLCreateModeStatPathAndBytesable;
+import org.apache.curator.framework.api.UnhandledErrorListener;
 import org.apache.curator.framework.api.transaction.OperationType;
 import org.apache.curator.framework.api.transaction.TransactionCreateBuilder;
 import org.apache.curator.framework.api.transaction.TransactionCreateBuilder2;
@@ -40,10 +63,6 @@ import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.server.DataTree;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, 
BackgroundOperation<PathAndBytes>, ErrorListenerPathAndBytesable<String>
 {
@@ -778,6 +797,8 @@ public class CreateBuilderImpl implements CreateBuilder, 
CreateBuilder2, Backgro
                 {
                     if ( 
!client.getZookeeperClient().getRetryPolicy().allowRetry(e) )
                     {
+                        final CuratorEvent event = makeCuratorEvent(client, 
e.code().intValue(), e.getPath(), null, e.getPath(), null);
+                        
client.processBackgroundOperation(mainOperationAndData, event);
                         throw e;
                     }
                     // otherwise safe to ignore as it will get retried
@@ -873,12 +894,15 @@ public class CreateBuilderImpl implements CreateBuilder, 
CreateBuilder2, Backgro
     }
 
     private void sendBackgroundResponse(int rc, String path, Object ctx, 
String name, Stat stat, OperationAndData<PathAndBytes> operationAndData)
+    {
+        client.processBackgroundOperation(operationAndData, 
makeCuratorEvent(client, rc, path, ctx, name, stat));
+    }
+
+    private static CuratorEvent makeCuratorEvent(CuratorFrameworkImpl client, 
int rc, String path, Object ctx, String name, Stat stat)
     {
         path = client.unfixForNamespace(path);
         name = client.unfixForNamespace(name);
-
-        CuratorEvent event = new CuratorEventImpl(client, 
CuratorEventType.CREATE, rc, path, name, ctx, stat, null, null, null, null, 
null);
-        client.processBackgroundOperation(operationAndData, event);
+        return new CuratorEventImpl(client, CuratorEventType.CREATE, rc, path, 
name, ctx, stat, null, null, null, null, null);
     }
 
     private ACLCreateModePathAndBytesable<String> 
asACLCreateModePathAndBytesable()
diff --git 
a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
 
b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
index a7a22bfd..7f5c6816 100644
--- 
a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
+++ 
b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestModeledFramework.java
@@ -25,19 +25,32 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 import com.google.common.collect.Sets;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.ACLProvider;
 import org.apache.curator.framework.schema.Schema;
 import org.apache.curator.framework.schema.SchemaSet;
 import org.apache.curator.framework.schema.SchemaViolation;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.x.async.AsyncCuratorFramework;
 import org.apache.curator.x.async.AsyncStage;
+import org.apache.curator.x.async.api.CreateOption;
 import org.apache.curator.x.async.api.DeleteOption;
 import org.apache.curator.x.async.modeled.models.TestModel;
 import org.apache.curator.x.async.modeled.models.TestNewerModel;
 import org.apache.curator.x.async.modeled.versioned.Versioned;
 import org.apache.curator.x.async.modeled.versioned.VersionedModeledFramework;
+import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.ACL;
@@ -46,13 +59,6 @@ import org.apache.zookeeper.data.Stat;
 import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
 import org.junit.jupiter.api.Test;
 
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-
 public class TestModeledFramework extends TestModeledFrameworkBase
 {
     @Test
@@ -222,4 +228,62 @@ public class TestModeledFramework extends 
TestModeledFrameworkBase
             complete(authClient.update(new TestModel("John", "Galt", "Galt's 
Gulch", 42, BigInteger.valueOf(66))), (__, e) -> assertNull(e, "Should've 
succeeded"));
         }
     }
+
+    @Test
+    public void testExceptionHandling() throws Exception
+    {
+        final List<ACL> writeAcl = Collections.singletonList(new 
ACL(ZooDefs.Perms.WRITE, new Id("digest", 
DigestAuthenticationProvider.generateDigest("test:test"))));
+
+        // An ACLProvider is used to get the Write ACL (for the test user) for 
any path "/test/**".
+        final ACLProvider aclProvider = new ACLProvider() {
+            @Override
+            public List<ACL> getDefaultAcl() { return 
ZooDefs.Ids.READ_ACL_UNSAFE; }
+
+            @Override
+            public List<ACL> getAclForPath(String path)
+            {
+                // Any sub-path "/test/**" should only be writeable by the 
test user.
+                return path.startsWith("/test") ? writeAcl : getDefaultAcl();
+            }
+        };
+
+        try (CuratorFramework authorizedFramework = 
CuratorFrameworkFactory.builder()
+                .connectString(server.getConnectString())
+                .retryPolicy(new RetryOneTime(1))
+                .aclProvider(aclProvider)
+                .authorization("digest", "test:test".getBytes())
+                .build()) {
+
+            authorizedFramework.start();
+
+            // Create the parent path using the authorized framework, which 
will initially set the ACL accordingly.
+            
authorizedFramework.create().withMode(CreateMode.PERSISTENT).forPath("/test");
+        }
+
+        // Now attempt to set the sub-node using an unauthorized client.
+        try (CuratorFramework unauthorizedFramework = 
CuratorFrameworkFactory.builder()
+                .connectString(server.getConnectString())
+                .retryPolicy(new RetryOneTime(1))
+                .aclProvider(aclProvider)
+                .build()) {
+            unauthorizedFramework.start();
+
+            // I overrode the TestModel provided path with a multi-component 
path under the "/test" parent path
+            // (which was previously created with ACL protection).
+            ModelSpec<TestModel> aclModelSpec = 
ModelSpec.builder(ZPath.parse("/test/foo/bar"), modelSpec.serializer())
+                    
.withCreateOptions(EnumSet.of(CreateOption.createParentsIfNeeded, 
CreateOption.createParentsAsContainers))
+                    .build();
+
+            ModeledFramework<TestModel> noAuthClient = 
ModeledFramework.wrap(AsyncCuratorFramework.wrap(unauthorizedFramework), 
aclModelSpec);
+
+            noAuthClient.set(new TestModel("John", "Galt", "Galt's Gulch", 42, 
BigInteger.valueOf(66)))
+                    .toCompletableFuture()
+                    .get(timing.forWaiting().milliseconds(), 
TimeUnit.MILLISECONDS);
+            fail("expect to throw a NoAuth KeeperException");
+        }
+        catch (ExecutionException | CompletionException e)
+        {
+             assertTrue(e.getCause() instanceof 
KeeperException.NoAuthException);
+        }
+    }
 }

Reply via email to