added a resolving version that takes suppliers for parameters
Project: http://git-wip-us.apache.org/repos/asf/curator/repo Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/52b334c3 Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/52b334c3 Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/52b334c3 Branch: refs/heads/CURATOR-397 Commit: 52b334c30d82227ad7da3559976fa932fbbc5763 Parents: 22fdb29 Author: randgalt <[email protected]> Authored: Wed Apr 26 16:53:17 2017 -0500 Committer: randgalt <[email protected]> Committed: Wed Apr 26 16:53:17 2017 -0500 ---------------------------------------------------------------------- .../apache/curator/x/async/modeled/ZPath.java | 50 ++++++++++-- .../x/async/modeled/details/ZPathImpl.java | 86 ++++++++++++++------ .../curator/x/async/modeled/TestZPath.java | 13 +++ 3 files changed, 115 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/curator/blob/52b334c3/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java index ff84d26..f68679d 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/ZPath.java @@ -19,6 +19,9 @@ package org.apache.curator.x.async.modeled; import org.apache.curator.x.async.modeled.details.ZPathImpl; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; import java.util.regex.Pattern; /** @@ -58,12 +61,19 @@ public interface ZPath */ static ZPath from(String... names) { - ZPath path = root(); - for ( String n : names ) - { - path = path.at(n); - } - return path; + return ZPathImpl.from(names); + } + + /** + * Convert individual path names into a ZPath + * + * @param names path names + * @return ZPath + * @throws IllegalArgumentException if any of the names is invalid + */ + static ZPath from(List<String> names) + { + return ZPathImpl.from(names); } /** @@ -85,7 +95,33 @@ public interface ZPath * parameter nodes in the path * @return new resolved ZPath */ - ZPath resolved(Object... parameters); + default ZPath resolved(Object... parameters) + { + return resolved(Arrays.asList(parameters)); + } + + /** + * When creating paths, any node in the path can be set to {@link #parameterNodeName()}. + * At runtime, the ZPath can be "resolved" by replacing these nodes with values. + * + * @param parameters list of replacements. Must have be the same length as the number of + * parameter nodes in the path + * @return new resolved ZPath + */ + ZPath resolved(List<Object> parameters); + + /** + * An "auto" resolving version of this ZPath. i.e. if any of the path names is + * the {@link #parameterNodeName()} the ZPath must be resolved. This method + * creates a new ZPath that auto resolves by using the given parameter suppliers + * whenever needed. + * + * @param parameterSuppliers parameter suppliers + * @return new auto resolving ZNode + * @see #resolved(Object...) + * @see #parameterNodeName() + */ + ZPath resolving(List<Supplier<Object>> parameterSuppliers); /** * Return a ZPath that represents a child ZNode of this ZPath. e.g. http://git-wip-us.apache.org/repos/asf/curator/blob/52b334c3/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ZPathImpl.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ZPathImpl.java b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ZPathImpl.java index be03963..e728537 100644 --- a/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ZPathImpl.java +++ b/curator-x-async/src/main/java/org/apache/curator/x/async/modeled/details/ZPathImpl.java @@ -21,24 +21,28 @@ package org.apache.curator.x.async.modeled.details; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; import org.apache.curator.utils.ZKPaths; import org.apache.curator.x.async.modeled.ZPath; import org.apache.zookeeper.common.PathUtils; +import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.function.Supplier; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class ZPathImpl implements ZPath { - public static final ZPath root = new ZPathImpl(Collections.singletonList(ZKPaths.PATH_SEPARATOR), null); + public static final ZPath root = new ZPathImpl(Collections.singletonList(ZKPaths.PATH_SEPARATOR), null, null); public static final String parameter = "\u0000"; // PathUtils.validatePath() rejects this so it's useful for this purpose private final List<String> nodes; private final boolean isResolved; + private final List<Supplier<Object>> parameterSuppliers; public static ZPath parse(String fullPath) { @@ -47,20 +51,36 @@ public class ZPathImpl implements ZPath .addAll(Splitter.on(ZKPaths.PATH_SEPARATOR).omitEmptyStrings().splitToList(fullPath)) .build(); nodes.forEach(ZPathImpl::validate); - return new ZPathImpl(nodes, null); + return new ZPathImpl(nodes, null, null); + } + + public static ZPath from(String[] names) + { + return from(Arrays.asList(names)); + } + + public static ZPath from(List<String> names) + { + names = Objects.requireNonNull(names, "names cannot be null"); + names.forEach(ZPathImpl::validate); + List<String> nodes = ImmutableList.<String>builder() + .add(ZKPaths.PATH_SEPARATOR) + .addAll(names) + .build(); + return new ZPathImpl(nodes, null, null); } @Override public ZPath at(String child) { - return new ZPathImpl(nodes, child); + return new ZPathImpl(nodes, child, parameterSuppliers); } @Override public ZPath parent() { checkRootAccess(); - return new ZPathImpl(nodes.subList(0, nodes.size() - 1), null); + return new ZPathImpl(nodes.subList(0, nodes.size() - 1), null, parameterSuppliers); } @Override @@ -93,7 +113,6 @@ public class ZPathImpl implements ZPath @Override public String nodeName() { - checkResolved(); return nodes.get(nodes.size() - 1); } @@ -127,31 +146,35 @@ public class ZPathImpl implements ZPath } @Override - public ZPath resolved(Object... parameters) + public ZPath resolved(List<Object> parameters) { - List<String> nodeNames = Lists.newArrayList(); - int parameterIndex = 0; - for ( int i = 0; i < nodes.size(); ++i ) - { - String name = nodes.get(i); - if ( name.equals(parameter) ) - { - if ( parameterIndex >= parameters.length ) + Iterator<Object> iterator = parameters.iterator(); + List<String> nodeNames = nodes.stream() + .map(name -> { + if ( name.equals(parameter) ) { - throw new IllegalStateException(String.format("Parameter missing at index [%d] for [%s]", parameterIndex, nodes.toString())); + if ( !iterator.hasNext() ) + { + throw new IllegalStateException(String.format("Parameter missing for [%s]", nodes.toString())); + } + return iterator.next().toString(); } - nodeNames.add(parameters[parameterIndex++].toString()); - } - else - { - nodeNames.add(name); - } - } - return new ZPathImpl(nodeNames, null); + return name; + }) + .collect(Collectors.toList()); + return new ZPathImpl(nodeNames, null, parameterSuppliers); } - private ZPathImpl(List<String> nodes, String child) + @Override + public ZPath resolving(List<Supplier<Object>> parameterSuppliers) { + parameterSuppliers = Objects.requireNonNull(parameterSuppliers, "parameterSuppliers cannot be null"); + return new ZPathImpl(nodes, null, parameterSuppliers); + } + + private ZPathImpl(List<String> nodes, String child, List<Supplier<Object>> parameterSuppliers) + { + this.parameterSuppliers = parameterSuppliers; ImmutableList.Builder<String> builder = ImmutableList.<String>builder().addAll(nodes); if ( child != null ) { @@ -159,7 +182,7 @@ public class ZPathImpl implements ZPath builder.add(child); } this.nodes = builder.build(); - isResolved = !this.nodes.contains(parameter); + isResolved = (parameterSuppliers != null) || !this.nodes.contains(parameter); } private void checkRootAccess() @@ -180,6 +203,7 @@ public class ZPathImpl implements ZPath boolean addSeparator = false; StringBuilder str = new StringBuilder(); int size = parent ? (nodes.size() - 1) : nodes.size(); + int parameterIndex = 0; for ( int i = 0; i < size; ++i ) { if ( i > 1 ) @@ -187,7 +211,15 @@ public class ZPathImpl implements ZPath str.append(ZKPaths.PATH_SEPARATOR); } String value = nodes.get(i); - str.append(value.equals(parameter) ? ".*" : value); + if ( value.equals(parameter) ) + { + if ( (parameterSuppliers == null) || (parameterSuppliers.size() <= parameterIndex) ) + { + throw new IllegalStateException(String.format("Parameter supplier missing at index [%d] for [%s]", parameterIndex, nodes.toString())); + } + value = parameterSuppliers.get(parameterIndex++).get().toString(); + } + str.append(value); } return str.toString(); } http://git-wip-us.apache.org/repos/asf/curator/blob/52b334c3/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestZPath.java ---------------------------------------------------------------------- diff --git a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestZPath.java b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestZPath.java index 2ca38ca..8397ef5 100644 --- a/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestZPath.java +++ b/curator-x-async/src/test/java/org/apache/curator/x/async/modeled/TestZPath.java @@ -22,6 +22,8 @@ import org.apache.curator.utils.ZKPaths; import org.apache.curator.x.async.modeled.details.ZPathImpl; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; public class TestZPath { @@ -68,4 +70,15 @@ public class TestZPath ZPath path = ZPath.from("one", ZPath.parameterNodeName(), "two", ZPath.parameterNodeName()); Assert.assertEquals(path.resolved("a", "b"), ZPath.from("one", "a", "two", "b")); } + + @Test + public void testResolving() + { + ZPath path = ZPath.from("one", ZPath.parameterNodeName(), "two", ZPath.parameterNodeName()); + AtomicInteger count = new AtomicInteger(0); + ZPath resolving = path.resolving(Arrays.asList(() -> "x" + count.get(), () -> "y" + count.get())); + Assert.assertEquals(resolving.fullPath(), "/one/x0/two/y0"); + count.incrementAndGet(); + Assert.assertEquals(resolving.fullPath(), "/one/x1/two/y1"); + } }
