You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ib...@apache.org on 2021/02/03 09:21:43 UTC
[ignite-3] branch main updated: IGNITE-14102 ConfigurationUtil
class with escaping and searching in traversable tree methods. (#40)
This is an automated email from the ASF dual-hosted git repository.
ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new c9ebaef IGNITE-14102 ConfigurationUtil class with escaping and searching in traversable tree methods. (#40)
c9ebaef is described below
commit c9ebaef410abdebe4e126ef9822d9d585482d894
Author: ibessonov <be...@gmail.com>
AuthorDate: Wed Feb 3 12:21:22 2021 +0300
IGNITE-14102 ConfigurationUtil class with escaping and searching in traversable tree methods. (#40)
Signed-off-by: ibessonov <be...@gmail.com>
---
.../configuration/util/ConfigurationUtilTest.java | 174 +++++++++++++++++++++
.../configuration/util/ConfigurationUtil.java | 113 +++++++++++++
.../configuration/util/KeyNotFoundException.java | 31 ++++
3 files changed, 318 insertions(+)
diff --git a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/util/ConfigurationUtilTest.java b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/util/ConfigurationUtilTest.java
new file mode 100644
index 0000000..45cc921
--- /dev/null
+++ b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/util/ConfigurationUtilTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.ignite.configuration.util;
+
+import java.util.List;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.util.impl.ParentNode;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/** */
+public class ConfigurationUtilTest {
+ /** */
+ @Test
+ public void escape() {
+ assertEquals("foo", ConfigurationUtil.escape("foo"));
+
+ assertEquals("foo\\.bar", ConfigurationUtil.escape("foo.bar"));
+
+ assertEquals("foo\\\\bar", ConfigurationUtil.escape("foo\\bar"));
+
+ assertEquals("\\\\a\\.b\\\\c\\.", ConfigurationUtil.escape("\\a.b\\c."));
+ }
+
+ /** */
+ @Test
+ public void unescape() {
+ assertEquals("foo", ConfigurationUtil.unescape("foo"));
+
+ assertEquals("foo.bar", ConfigurationUtil.unescape("foo\\.bar"));
+
+ assertEquals("foo\\bar", ConfigurationUtil.unescape("foo\\\\bar"));
+
+ assertEquals("\\a.b\\c.", ConfigurationUtil.unescape("\\\\a\\.b\\\\c\\."));
+ }
+
+ /** */
+ @Test
+ public void split() {
+ assertEquals(List.of("a", "b.b", "c\\c", ""), ConfigurationUtil.split("a.b\\.b.c\\\\c."));
+ }
+
+ /** */
+ @Test
+ public void join() {
+ assertEquals("a.b\\.b.c\\\\c", ConfigurationUtil.join(List.of("a", "b.b", "c\\c")));
+ }
+
+ /** */
+ @Config
+ public static class ParentConfigurationSchema {
+ /** */
+ @NamedConfigValue
+ private NamedElementConfigurationSchema elements;
+ }
+
+ /** */
+ @Config
+ public static class NamedElementConfigurationSchema {
+ /** */
+ @ConfigValue
+ private ChildConfigurationSchema child;
+ }
+
+ /** */
+ @Config
+ public static class ChildConfigurationSchema {
+ /** */
+ @Value
+ private String str;
+ }
+
+ /** */
+ @Test
+ public void findSuccessfully() {
+ var parent = new ParentNode();
+
+ parent.changeElements(elements ->
+ elements.put("name", element ->
+ element.changeChild(child ->
+ child.changeStr("value")
+ )
+ )
+ );
+
+ assertSame(
+ parent,
+ ConfigurationUtil.find(List.of(), parent)
+ );
+
+ assertSame(
+ parent.elements(),
+ ConfigurationUtil.find(List.of("elements"), parent)
+ );
+
+ assertSame(
+ parent.elements().get("name"),
+ ConfigurationUtil.find(List.of("elements", "name"), parent)
+ );
+
+ assertSame(
+ parent.elements().get("name").child(),
+ ConfigurationUtil.find(List.of("elements", "name", "child"), parent)
+ );
+
+ assertSame(
+ parent.elements().get("name").child().str(),
+ ConfigurationUtil.find(List.of("elements", "name", "child", "str"), parent)
+ );
+ }
+
+ /** */
+ @Test
+ public void findNulls() {
+ var parent = new ParentNode();
+
+ assertNull(ConfigurationUtil.find(List.of("elements", "name"), parent));
+
+ parent.changeElements(elements -> elements.put("name", element -> {}));
+
+ assertNull(ConfigurationUtil.find(List.of("elements", "name", "child"), parent));
+
+ parent.elements().get("name").changeChild(child -> {});
+
+ assertNull(ConfigurationUtil.find(List.of("elements", "name", "child", "str"), parent));
+ }
+
+ /** */
+ @Test
+ public void findUnsuccessfully() {
+ var parent = new ParentNode();
+
+ assertThrows(
+ KeyNotFoundException.class,
+ () -> ConfigurationUtil.find(List.of("elements", "name", "child"), parent)
+ );
+
+ parent.changeElements(elements -> elements.put("name", element -> {}));
+
+ assertThrows(
+ KeyNotFoundException.class,
+ () -> ConfigurationUtil.find(List.of("elements", "name", "child", "str"), parent)
+ );
+
+ parent.elements().get("name").changeChild(child -> child.changeStr("value"));
+
+ assertThrows(
+ KeyNotFoundException.class,
+ () -> ConfigurationUtil.find(List.of("elements", "name", "child", "str", "foo"), parent)
+ );
+ }
+}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/util/ConfigurationUtil.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/util/ConfigurationUtil.java
new file mode 100644
index 0000000..c752fc8
--- /dev/null
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/util/ConfigurationUtil.java
@@ -0,0 +1,113 @@
+/*
+ * 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.ignite.configuration.util;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.configuration.tree.InnerNode;
+import org.apache.ignite.configuration.tree.NamedListNode;
+import org.apache.ignite.configuration.tree.TraversableTreeNode;
+
+/** */
+public interface ConfigurationUtil {
+ /** */
+ static String escape(String key) {
+ return key.replaceAll("([.\\\\])", "\\\\$1");
+ }
+
+ /** */
+ static String unescape(String key) {
+ return key.replaceAll("\\\\([.\\\\])", "$1");
+ }
+
+ /** */
+ static List<String> split(String keys) {
+ String[] split = keys.split("(?<!\\\\)[.]", -1);
+
+ for (int i = 0; i < split.length; i++)
+ split[i] = unescape(split[i]);
+
+ return Arrays.asList(split);
+ }
+
+ /** */
+ static String join(List<String> keys) {
+ return keys.stream().map(ConfigurationUtil::escape).collect(Collectors.joining("."));
+ }
+
+ /**
+ * Search for the configuration node by the list of keys.
+ *
+ * @param keys Random access list with keys.
+ * @param node Node where method will search for subnode.
+ * @return Either {@link TraversableTreeNode} or {@link Serializable} depending on the keys and schema.
+ * @throws KeyNotFoundException If node is not found.
+ */
+ static Object find(List<String> keys, TraversableTreeNode node) throws KeyNotFoundException {
+ assert keys instanceof RandomAccess : keys.getClass();
+
+ var visitor = new ConfigurationVisitor() {
+ /** */
+ private int i;
+
+ /** */
+ private Object res;
+
+ @Override public void visitLeafNode(String key, Serializable val) {
+ if (i != keys.size())
+ throw new KeyNotFoundException("Configuration value '" + join(keys.subList(0, i)) + "' is a leaf");
+
+ res = val;
+ }
+
+ @Override public void visitInnerNode(String key, InnerNode node) {
+ if (i == keys.size())
+ res = node;
+ else if (node == null)
+ throw new KeyNotFoundException("Configuration node '" + join(keys.subList(0, i)) + "' is null");
+ else {
+ try {
+ node.traverseChild(keys.get(i++), this);
+ }
+ catch (NoSuchElementException e) {
+ throw new KeyNotFoundException("Configuration '" + join(keys.subList(0, i)) + "' is not found");
+ }
+ }
+ }
+
+ @Override public <N extends InnerNode> void visitNamedListNode(String key, NamedListNode<N> node) {
+ if (i == keys.size())
+ res = node;
+ else {
+ String name = keys.get(i++);
+
+ visitInnerNode(name, node.get(name));
+ }
+ }
+ };
+
+ node.accept(null, visitor);
+
+ return visitor.res;
+ }
+}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/util/KeyNotFoundException.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/util/KeyNotFoundException.java
new file mode 100644
index 0000000..90c605f
--- /dev/null
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/util/KeyNotFoundException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.ignite.configuration.util;
+
+/** */
+public class KeyNotFoundException extends RuntimeException {
+ /** Serial version uid. */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * @param msg Message.
+ */
+ public KeyNotFoundException(String msg) {
+ super(msg);
+ }
+}