You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2020/05/15 20:00:54 UTC

[curator] branch master updated: CURATOR-569

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

randgalt 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 f73b8fb  CURATOR-569
f73b8fb is described below

commit f73b8fbb0429b7df934ee17f30f2846e7391deee
Author: chevaris <ev...@yahoo.es>
AuthorDate: Sun May 10 18:41:05 2020 +0200

    CURATOR-569
    
    - New methods to handle protected ZNode names
---
 .../curator/framework/api/CreateBuilderMain.java   |  15 +-
 .../curator/framework/imps/CreateBuilderImpl.java  |  18 +--
 .../curator/framework/imps/ProtectedMode.java      |   8 +-
 .../curator/framework/imps/ProtectedUtils.java     | 165 +++++++++++++++++++++
 .../apache/curator/framework/imps/TestCreate.java  |  94 +++++++++---
 .../curator/framework/imps/TestFrameworkEdges.java |   4 +-
 .../curator/framework/imps/TestFramework.java      |  12 +-
 7 files changed, 263 insertions(+), 53 deletions(-)

diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/CreateBuilderMain.java b/curator-framework/src/main/java/org/apache/curator/framework/api/CreateBuilderMain.java
index 3d076b2..a90ad3e 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/api/CreateBuilderMain.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/api/CreateBuilderMain.java
@@ -18,6 +18,9 @@
  */
 package org.apache.curator.framework.api;
 
+import java.util.UUID;
+
+import org.apache.curator.framework.imps.ProtectedUtils;
 import org.apache.zookeeper.CreateMode;
 
 public interface CreateBuilderMain extends
@@ -27,6 +30,7 @@ public interface CreateBuilderMain extends
     Compressible<CreateBackgroundModeStatACLable>,
     Statable<CreateProtectACLCreateModePathAndBytesable<String>>
 {
+
     /**
      * Causes any parent nodes to get created if they haven't already been
      *
@@ -74,9 +78,14 @@ public interface CreateBuilderMain extends
      *
      * <p>
      *     Putting the create builder into protection mode works around this.
-     *     The name of the node that is created is prefixed with a GUID. If node creation fails
-     *     the normal retry mechanism will occur. On the retry, the parent path is first searched
-     *     for a node that has the GUID in it. If that node is found, it is assumed to be the lost
+     *     The name of the node that is created is prefixed with a 40 characters string that is the concatenation of
+     *     <ul>
+     *         <li>{@value ProtectedUtils#PROTECTED_PREFIX}
+     *         <li>Canonical text representation of a random generated UUID as produced by {@link UUID#toString()}
+     *         <li>{@value ProtectedUtils#PROTECTED_SEPARATOR}
+     *     </ul>
+     *     If node creation fails the normal retry mechanism will occur. On the retry, the parent path is first searched
+     *     for a node that has previous described prefix in it. If that node is found, it is assumed to be the lost
      *     node that was successfully created on the first try and is returned to the caller.
      * </p>
      *
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 2ccc173..cd43f07 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
@@ -64,9 +64,6 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
     @VisibleForTesting
     boolean failNextCreateForTesting = false;
 
-    @VisibleForTesting
-    static final String PROTECTED_PREFIX = "_c_";
-
     CreateBuilderImpl(CuratorFrameworkImpl client)
     {
         this.client = client;
@@ -749,11 +746,6 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
         };
     }
 
-    private static String getProtectedPrefix(String protectedId)
-    {
-        return PROTECTED_PREFIX + protectedId + "-";
-    }
-
     static <T> void backgroundCreateParentsThenNode(final CuratorFrameworkImpl client, final OperationAndData<T> mainOperationAndData, final String path, Backgrounding backgrounding, final InternalACLProvider aclProvider, final boolean createParentsAsContainers)
     {
         BackgroundOperation<T> operation = new BackgroundOperation<T>()
@@ -1221,13 +1213,7 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
     @VisibleForTesting
     String adjustPath(String path) throws Exception
     {
-        if ( protectedMode.doProtected() )
-        {
-            ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(path);
-            String name = getProtectedPrefix(protectedMode.protectedId()) + pathAndNode.getNode();
-            path = ZKPaths.makePath(pathAndNode.getPath(), name);
-        }
-        return path;
+        return ProtectedUtils.toProtectedZNodePath(path, protectedMode.protectedId());
     }
 
     /**
@@ -1240,7 +1226,7 @@ public class CreateBuilderImpl implements CreateBuilder, CreateBuilder2, Backgro
      */
     static String findNode(final List<String> children, final String path, final String protectedId)
     {
-        final String protectedPrefix = getProtectedPrefix(protectedId);
+        final String protectedPrefix = ProtectedUtils.getProtectedPrefix(protectedId);
         String foundNode = Iterables.find
             (
                 children,
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedMode.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedMode.java
index 5c2f052..7244cc4 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedMode.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedMode.java
@@ -30,7 +30,6 @@ import java.util.UUID;
 class ProtectedMode
 {
     private final Logger log = LoggerFactory.getLogger(getClass());
-    private volatile boolean doProtected = false;
     private volatile String protectedId = null;
     private volatile long sessionId = 0;
 
@@ -39,7 +38,6 @@ class ProtectedMode
      */
     void setProtectedMode()
     {
-        doProtected = true;
         resetProtectedId();
     }
 
@@ -56,7 +54,7 @@ class ProtectedMode
      */
     boolean doProtected()
     {
-        return doProtected;
+        return (protectedId != null);
     }
 
     /**
@@ -76,7 +74,7 @@ class ProtectedMode
      */
     void checkSetSessionId(CuratorFrameworkImpl client, CreateMode createMode) throws Exception
     {
-        if ( doProtected && (sessionId == 0) && createMode.isEphemeral() )
+        if ( doProtected() && (sessionId == 0) && createMode.isEphemeral() )
         {
             sessionId = client.getZooKeeper().getSessionId();
         }
@@ -93,7 +91,7 @@ class ProtectedMode
      */
     String validateFoundNode(CuratorFrameworkImpl client, CreateMode createMode, String foundNode) throws Exception
     {
-        if ( doProtected && createMode.isEphemeral() )
+        if ( doProtected() && createMode.isEphemeral() )
         {
             long clientSessionId = client.getZooKeeper().getSessionId();
             if ( this.sessionId != clientSessionId )
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedUtils.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedUtils.java
new file mode 100644
index 0000000..a5489f2
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ProtectedUtils.java
@@ -0,0 +1,165 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.imps;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.curator.framework.api.CreateBuilderMain;
+import org.apache.curator.utils.ZKPaths;
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Utility class to handle ZNode names when using {@link CreateBuilderMain#withProtection()}
+ */
+public final class ProtectedUtils
+{
+
+    private ProtectedUtils()
+    {
+        throw new RuntimeException("Protected Utils is a helper class");
+    }
+
+    /**
+     * First 3 characters in the prefix on ZNode names when using {@link CreateBuilderMain#withProtection()}
+     */
+    @VisibleForTesting
+    static final String PROTECTED_PREFIX = "_c_";
+
+    /**
+     * Last character used in the prefix on ZNode names when using {@link CreateBuilderMain#withProtection()}
+     */
+    @VisibleForTesting
+    static final char PROTECTED_SEPARATOR = '-';
+
+    /**
+     * Prefix length on ZNode name when using {@link CreateBuilderMain#withProtection()}
+     */
+    @VisibleForTesting
+    static final int PROTECTED_PREFIX_WITH_UUID_LENGTH = PROTECTED_PREFIX.length() + 36 // UUID canonical text representation produced by {@link UUID#toString()}
+        + 1; // Separator length
+
+    /**
+     * Provides a prefix to be prepended to a ZNode name when protected. The method assumes that the provided string
+     * adjusts to the required format
+     *
+     * @param protectedId canonical text representation of a UUID
+     * @return string that concatenates {@value #PROTECTED_PREFIX}, the given id and {@value #PROTECTED_SEPARATOR}
+     */
+    public static String getProtectedPrefix(final String protectedId)
+    {
+        return PROTECTED_PREFIX + protectedId + PROTECTED_SEPARATOR;
+    }
+
+    /** Extracts protectedId assuming provided name has a valid protected format */
+    private static String extractProtectedIdInternal(final String znodeName)
+    {
+        return znodeName.substring(PROTECTED_PREFIX.length(), PROTECTED_PREFIX_WITH_UUID_LENGTH - 1);
+    }
+
+    /**
+     * Utility method to determine if a given ZNode name starts with Curator's generated protected prefix.
+     *
+     * @param znodeName ZNode name
+     * @return {@code true} if the given ZNode name starts with Curator's generated protected prefix
+     */
+    public static boolean isProtectedZNode(final String znodeName)
+    {
+        if ( znodeName.length() > PROTECTED_PREFIX_WITH_UUID_LENGTH && znodeName.startsWith(PROTECTED_PREFIX) && znodeName.charAt(PROTECTED_PREFIX_WITH_UUID_LENGTH - 1) == PROTECTED_SEPARATOR )
+        {
+            try
+            {
+                //noinspection ResultOfMethodCallIgnored
+                UUID.fromString(extractProtectedIdInternal(znodeName));
+                return true;
+            }
+            catch ( IllegalArgumentException e )
+            {
+                // Not an UUID
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Utility method to remove Curator's generated protected prefix if present
+     *
+     * @param znodeName ZNode name
+     * @return string without Curator's generated protected prefix if present; original string if prefix not present
+     */
+    public static String normalize(final String znodeName)
+    {
+        return isProtectedZNode(znodeName) ? znodeName.substring(PROTECTED_PREFIX_WITH_UUID_LENGTH) : znodeName;
+    }
+
+    /**
+     * Utility method to provide a path removing Curator's generated protected prefix if present in the ZNode name
+     *
+     * @param path ZNode path
+     * @return string without Curator's generated protected prefix if present in ZNode name; original string if prefix not present
+     */
+    public static String normalizePath(final String path)
+    {
+        final ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(path);
+        final String name = pathAndNode.getNode();
+        return isProtectedZNode(name) ? ZKPaths.makePath(pathAndNode.getPath(), normalize(name)) : path;
+    }
+
+    /**
+     * Extracts protectedId in case the provided name is protected
+     *
+     * @param znodeName name of the ZNode
+     * @return Optional with protectedId if the name is protected or {@code Optional#empty()}
+     */
+    public static Optional<String> extractProtectedId(final String znodeName)
+    {
+        return Optional.ofNullable(isProtectedZNode(znodeName) ? extractProtectedIdInternal(znodeName) : null);
+    }
+
+    /**
+     * Converts a given ZNode name to protected format
+     *
+     * @param znodeName name to be converted (e.g. 'name1')
+     * @param protectedId UUID canonical text representation used in protection mode (e.g. '53345f98-9423-4e0c-a7b5-9f819e3ec2e1') 
+     * @return name with protected mode prefix (e.g. '_c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-name1')
+     *         or the same name if protectedId is {@code null}
+     */
+    public static String toProtectedZNode(final String znodeName, final String protectedId)
+    {
+        return (protectedId == null) ? znodeName : getProtectedPrefix(protectedId) + znodeName;
+    }
+
+    /**
+     * Converts a given path to protected format
+     *
+     * @param path complete path to be converted (e.g. '/root/path1')
+     * @param protectedId UUID canonical text representation used in protection mode (e.g. '53345f98-9423-4e0c-a7b5-9f819e3ec2e1') 
+     * @return path with protected mode prefix (e.g. '/root/_c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-path1')
+     *         or the same path if protectedId is {@code null}
+     */
+    public static String toProtectedZNodePath(final String path, final String protectedId)
+    {
+        if ( protectedId == null )
+        {
+            return path;
+        }
+        final ZKPaths.PathAndNode pathAndNode = ZKPaths.getPathAndNode(path);
+        return ZKPaths.makePath(pathAndNode.getPath(), toProtectedZNode(pathAndNode.getNode(), protectedId));
+    }
+}
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreate.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreate.java
index 55ef622..dcc0dda 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreate.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestCreate.java
@@ -6,9 +6,9 @@
  * 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
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
  * 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
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 package org.apache.curator.framework.imps;
 
 import org.apache.curator.framework.CuratorFramework;
@@ -26,13 +27,15 @@ import org.apache.curator.framework.api.CuratorEvent;
 import org.apache.curator.retry.RetryOneTime;
 import org.apache.curator.test.BaseClassForTests;
 import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.utils.ZKPaths;
+import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.data.ACL;
 import org.testng.Assert;
 import org.testng.annotations.Test;
-
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -54,10 +57,12 @@ public class TestCreate extends BaseClassForTests
         @Override
         public List<ACL> getAclForPath(String path)
         {
-            switch (path)
+            switch ( path )
             {
-                case "/bar" : return READ_CREATE;
-                case "/bar/foo" : return READ_CREATE_WRITE;
+            case "/bar":
+                return READ_CREATE;
+            case "/bar/foo":
+                return READ_CREATE_WRITE;
             }
             return null;
         }
@@ -66,17 +71,17 @@ public class TestCreate extends BaseClassForTests
     private CuratorFramework createClient(ACLProvider aclProvider)
     {
         return CuratorFrameworkFactory.builder().
-                aclProvider(aclProvider).
-                connectString(server.getConnectString()).
-                retryPolicy(new RetryOneTime(1)).
-                build();
+            aclProvider(aclProvider).
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build();
     }
 
     /**
      * Tests that the ACL list provided to the create builder is used for creating the parents.
      */
     @Test
-    public void  testCreateWithParentsWithAcl() throws Exception
+    public void testCreateWithParentsWithAcl() throws Exception
     {
         CuratorFramework client = createClient(new DefaultACLProvider());
         try
@@ -98,7 +103,7 @@ public class TestCreate extends BaseClassForTests
     }
 
     @Test
-    public void  testCreateWithParentsWithAclApplyToParents() throws Exception
+    public void testCreateWithParentsWithAclApplyToParents() throws Exception
     {
         CuratorFramework client = createClient(new DefaultACLProvider());
         try
@@ -123,7 +128,7 @@ public class TestCreate extends BaseClassForTests
      * Tests that the ACL list provided to the create builder is used for creating the parents.
      */
     @Test
-    public void  testCreateWithParentsWithAclInBackground() throws Exception
+    public void testCreateWithParentsWithAclInBackground() throws Exception
     {
         CuratorFramework client = createClient(new DefaultACLProvider());
         try
@@ -154,7 +159,7 @@ public class TestCreate extends BaseClassForTests
     }
 
     @Test
-    public void  testCreateWithParentsWithAclApplyToParentsInBackground() throws Exception
+    public void testCreateWithParentsWithAclApplyToParentsInBackground() throws Exception
     {
         CuratorFramework client = createClient(new DefaultACLProvider());
         try
@@ -188,7 +193,7 @@ public class TestCreate extends BaseClassForTests
      * Tests that if no ACL list provided to the create builder, then the ACL list is created based on the client's ACLProvider.
      */
     @Test
-    public void  testCreateWithParentsWithoutAcl() throws Exception
+    public void testCreateWithParentsWithoutAcl() throws Exception
     {
         CuratorFramework client = createClient(testACLProvider);
         try
@@ -214,7 +219,7 @@ public class TestCreate extends BaseClassForTests
      * Tests that if no ACL list provided to the create builder, then the ACL list is created based on the client's ACLProvider.
      */
     @Test
-    public void  testCreateWithParentsWithoutAclInBackground() throws Exception
+    public void testCreateWithParentsWithoutAclInBackground() throws Exception
     {
         CuratorFramework client = createClient(testACLProvider);
         try
@@ -246,4 +251,59 @@ public class TestCreate extends BaseClassForTests
             CloseableUtils.closeQuietly(client);
         }
     }
+
+    @Test
+    public void testCreateProtectedUtils() throws Exception
+    {
+        try (CuratorFramework client = CuratorFrameworkFactory.builder().
+            connectString(server.getConnectString()).
+            retryPolicy(new RetryOneTime(1)).
+            build())
+        {
+            client.start();
+            client.blockUntilConnected();
+            client.create().forPath("/parent");
+            Assert.assertEquals(client.getChildren().forPath("/parent").size(), 0);
+            client.create().withProtection().withMode(CreateMode.EPHEMERAL).forPath("/parent/test");
+            final List<String> children = client.getChildren().forPath("/parent");
+            Assert.assertEquals(1, children.size());
+            final String testZNodeName = children.get(0);
+            Assert.assertEquals(testZNodeName.length(), ProtectedUtils.PROTECTED_PREFIX_WITH_UUID_LENGTH + "test".length());
+            Assert.assertTrue(testZNodeName.startsWith(ProtectedUtils.PROTECTED_PREFIX));
+            Assert.assertEquals(testZNodeName.charAt(ProtectedUtils.PROTECTED_PREFIX_WITH_UUID_LENGTH - 1), ProtectedUtils.PROTECTED_SEPARATOR);
+            Assert.assertTrue(ProtectedUtils.isProtectedZNode(testZNodeName));
+            Assert.assertEquals(ProtectedUtils.normalize(testZNodeName), "test");
+            Assert.assertFalse(ProtectedUtils.isProtectedZNode("parent"));
+            Assert.assertEquals(ProtectedUtils.normalize("parent"), "parent");
+        }
+    }
+
+    @Test
+    public void testProtectedUtils() throws Exception
+    {
+        String name = "_c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-yo";
+        Assert.assertTrue(ProtectedUtils.isProtectedZNode(name));
+        Assert.assertEquals(ProtectedUtils.normalize(name), "yo");
+        Assert.assertEquals(ProtectedUtils.extractProtectedId(name).get(), "53345f98-9423-4e0c-a7b5-9f819e3ec2e1");
+        name = "c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-yo";
+        Assert.assertFalse(ProtectedUtils.isProtectedZNode(name));
+        Assert.assertEquals(ProtectedUtils.normalize(name), name);
+        Assert.assertEquals(ProtectedUtils.extractProtectedId(name), Optional.<String>empty());
+        name = "_c_53345f98-hola-4e0c-a7b5-9f819e3ec2e1-yo";
+        Assert.assertFalse(ProtectedUtils.isProtectedZNode(name));
+        Assert.assertEquals(ProtectedUtils.normalize(name), name);
+        Assert.assertEquals(ProtectedUtils.extractProtectedId(name), Optional.<String>empty());
+        name = "_c_53345f98-hola-4e0c-a7b5-9f819e3ec2e1+yo";
+        Assert.assertFalse(ProtectedUtils.isProtectedZNode(name));
+        Assert.assertEquals(ProtectedUtils.normalize(name), name);
+        Assert.assertEquals(ProtectedUtils.extractProtectedId(name), Optional.<String>empty());
+        name = "_c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-yo";
+        Assert.assertEquals(name, ProtectedUtils.toProtectedZNode("yo", "53345f98-9423-4e0c-a7b5-9f819e3ec2e1"));
+        Assert.assertEquals("yo", ProtectedUtils.toProtectedZNode("yo", null));
+        String path = ZKPaths.makePath("hola", "yo");
+        Assert.assertEquals(ProtectedUtils.toProtectedZNodePath(path, "53345f98-9423-4e0c-a7b5-9f819e3ec2e1"), ZKPaths.makePath("hola", name));
+        Assert.assertEquals(ProtectedUtils.toProtectedZNodePath(path, null), path);
+        path = ZKPaths.makePath("hola", name);
+        Assert.assertEquals(ProtectedUtils.normalizePath(path), "/hola/yo");
+    }
 }
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
index 1c85c0e..3e7754a 100644
--- a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestFrameworkEdges.java
@@ -521,7 +521,7 @@ public class TestFrameworkEdges extends BaseClassForTests
             };
             createBuilder.withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).inBackground(callback).forPath("/");
             String ourPath = queue.poll(timing.forWaiting().seconds(), TimeUnit.SECONDS);
-            Assert.assertTrue(ourPath.startsWith(ZKPaths.makePath("/", CreateBuilderImpl.PROTECTED_PREFIX)));
+            Assert.assertTrue(ourPath.startsWith(ZKPaths.makePath("/", ProtectedUtils.PROTECTED_PREFIX)));
             Assert.assertFalse(createBuilder.failNextCreateForTesting);
         }
         finally
@@ -540,7 +540,7 @@ public class TestFrameworkEdges extends BaseClassForTests
             CreateBuilderImpl createBuilder = (CreateBuilderImpl)client.create();
             createBuilder.failNextCreateForTesting = true;
             String ourPath = createBuilder.withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/");
-            Assert.assertTrue(ourPath.startsWith(ZKPaths.makePath("/", CreateBuilderImpl.PROTECTED_PREFIX)));
+            Assert.assertTrue(ourPath.startsWith(ZKPaths.makePath("/", ProtectedUtils.PROTECTED_PREFIX)));
             Assert.assertFalse(createBuilder.failNextCreateForTesting);
         }
         finally
diff --git a/curator-x-async/src/test/java/org/apache/curator/framework/imps/TestFramework.java b/curator-x-async/src/test/java/org/apache/curator/framework/imps/TestFramework.java
index 27a84d0..395c4fd 100644
--- a/curator-x-async/src/test/java/org/apache/curator/framework/imps/TestFramework.java
+++ b/curator-x-async/src/test/java/org/apache/curator/framework/imps/TestFramework.java
@@ -49,7 +49,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
-import java.util.UUID;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
@@ -408,16 +407,9 @@ public class TestFramework extends BaseClassForTests
             AsyncCuratorFramework async = AsyncCuratorFramework.wrap(client);
             String path = async.create().withOptions(Collections.singleton(CreateOption.doProtected)).forPath("/yo").toCompletableFuture().get();
             String node = ZKPaths.getNodeFromPath(path);
-            Assert.assertTrue(node.startsWith(CreateBuilderImpl.PROTECTED_PREFIX), node);
-
             // CURATOR-489: confirm that the node contains a valid UUID, eg '_c_53345f98-9423-4e0c-a7b5-9f819e3ec2e1-yo'
-            int expectedProtectedIdLength = 36; // '53345f98-9423-4e0c-a7b5-9f819e3ec2e1'
-            int delimeterLength = 1; // '-'
-            int expectedNodeLength = CreateBuilderImpl.PROTECTED_PREFIX.length() + expectedProtectedIdLength + delimeterLength + "yo".length();
-            Assert.assertEquals(node.length(), expectedNodeLength);
-            int uuidStart = CreateBuilderImpl.PROTECTED_PREFIX.length();
-            String protectedId = node.substring(uuidStart, uuidStart + expectedProtectedIdLength);
-            UUID.fromString(protectedId); // will throw if token is not a UUID
+            Assert.assertTrue(ProtectedUtils.isProtectedZNode(node));
+            Assert.assertEquals(ProtectedUtils.normalize(node), "yo");
         }
         finally
         {