diff options
author | Harald Musum <musum@yahooinc.com> | 2023-09-07 12:25:37 +0200 |
---|---|---|
committer | Harald Musum <musum@yahooinc.com> | 2023-09-07 12:25:37 +0200 |
commit | cac205f35b56d0bd584013b79b88a6635dee5ab4 (patch) | |
tree | bcf8461b3091c44ae78e5d9355a2109ba7d6a77a /configgen | |
parent | daba552c567f1fcb9e300ae65825c1d97cedbb5e (diff) |
Support optional 'path' config type
Initial work needed for this to work (config definition and config library)
Diffstat (limited to 'configgen')
10 files changed, 127 insertions, 13 deletions
diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java index 6cd344466e4..12469d7a3ef 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java @@ -4,10 +4,12 @@ package com.yahoo.config.codegen; import com.yahoo.config.codegen.LeafCNode.FileLeaf; import com.yahoo.config.codegen.LeafCNode.ModelLeaf; import com.yahoo.config.codegen.LeafCNode.PathLeaf; +import com.yahoo.config.codegen.LeafCNode.OptionalPathLeaf; import com.yahoo.config.codegen.LeafCNode.UrlLeaf; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import static com.yahoo.config.codegen.ConfigGenerator.boxedDataType; @@ -89,7 +91,9 @@ public class BuilderGenerator { private static String getUninitializedScalars(InnerCNode node) { List<String> scalarsWithoutDefault = new ArrayList<>(); for (CNode child : node.getChildren()) { - if (child instanceof LeafCNode && (!child.isArray && !child.isMap && ((LeafCNode) child).getDefaultValue() == null)) { + if (child instanceof LeafCNode + && (!child.isArray && !child.isMap && ((LeafCNode) child).getDefaultValue() == null) + && (! (child instanceof OptionalPathLeaf))) { scalarsWithoutDefault.add("\"" + child.getName() + "\""); } } @@ -109,7 +113,11 @@ public class BuilderGenerator { } else if (node instanceof InnerCNode) { return String.format("public %s %s = new %s();", builderType(node), node.getName(), builderType(node)); } else if (node instanceof LeafCNode) { - return String.format("private %s %s = null;", boxedBuilderType((LeafCNode) node), node.getName()); + String boxedBuilderType = boxedBuilderType((LeafCNode) node); + if (boxedBuilderType.startsWith("Optional<")) + return String.format("private %s %s = Optional.empty();", boxedBuilderType, node.getName()); + else + return String.format("private %s %s = null;", boxedBuilderType, node.getName()); } else { throw new IllegalStateException("Cannot produce builder field definition for node"); // Should not happen } @@ -207,6 +215,11 @@ public class BuilderGenerator { private static String privateLeafNodeSetter(LeafCNode n) { if ("String".equals(builderType(n)) || "FileReference".equals(builderType(n))) { return ""; + } else if ("Optional<FileReference>".equals(builderType(n))) { + return "\n\n" + // + "private Builder " + n.getName() + "(String " + INTERNAL_PREFIX + "value) {\n" + // + " return " + n.getName() + "(" + builderType(n) + ".of(" + INTERNAL_PREFIX + "value));\n" + // + "}"; } else { return "\n\n" + // "private Builder " + n.getName() + "(String " + INTERNAL_PREFIX + "value) {\n" + // @@ -270,14 +283,24 @@ public class BuilderGenerator { : ""; String bType = builderType(n); - String stringSetter = ""; - if ( ! "String".equals(bType) && ! "FileReference".equals(bType) && ! "ModelReference".equals(bType)) { + String privateSetter = ""; + if ( ! Set.of("String", "FileReference", "ModelReference", "Optional<FileReference>").contains(bType)) { String type = boxedDataType(n); if ("UrlReference".equals(bType)) type = bType; - stringSetter = String.format("\nprivate Builder %s(String %svalue) {\n" + - " return %s(%s.valueOf(%svalue));\n" + // - "}", name, INTERNAL_PREFIX, name, type, INTERNAL_PREFIX); + // + privateSetter = String.format(""" + + private Builder %s(String %svalue) { + return %s(%s.valueOf(%svalue)); + }""", name, INTERNAL_PREFIX, name, type, INTERNAL_PREFIX); + } else if ("Optional<FileReference>".equals(bType)) { + // + privateSetter = String.format(""" + + private Builder %s(FileReference %svalue) { + return %s(Optional.of(%svalue)); + }""", name, INTERNAL_PREFIX, name, INTERNAL_PREFIX); } String getNullGuard = bType.equals(boxedBuilderType(n)) ? String.format( @@ -286,7 +309,7 @@ public class BuilderGenerator { return String.format("public Builder %s(%s %svalue) {%s\n" + " %s = %svalue;\n" + // "%s", name, bType, INTERNAL_PREFIX, getNullGuard, name, INTERNAL_PREFIX, signalInitialized) + - " return this;" + "\n}\n" + stringSetter; + " return this;" + "\n}\n" + privateSetter; } } @@ -307,6 +330,8 @@ public class BuilderGenerator { return name + "(" + nodeClass(child) + ".toFileReferenceMap(config." + name + "));"; } else if (child instanceof PathLeaf) { return name + "(config." + name + ".getFileReference());"; + } else if (child instanceof OptionalPathLeaf) { + return name + "(config." + name + ".getFileReference());"; } else if (child instanceof UrlLeaf && isArray) { return name + "(" + nodeClass(child) + ".toUrlReferences(config." + name + "));"; } else if (child instanceof UrlLeaf && isMap) { @@ -408,6 +433,8 @@ public class BuilderGenerator { return "String"; } else if (node instanceof PathLeaf) { return "FileReference"; + } else if (node instanceof OptionalPathLeaf) { + return "Optional<FileReference>"; } else if (node instanceof UrlLeaf) { return "UrlReference"; } else if (node instanceof ModelLeaf) { @@ -424,6 +451,8 @@ public class BuilderGenerator { return "String"; } else if (node instanceof PathLeaf) { return "FileReference"; + } else if (node instanceof OptionalPathLeaf) { + return "Optional<FileReference>"; } else if (node instanceof UrlLeaf) { return "UrlReference"; } else if (node instanceof ModelLeaf) { diff --git a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java index cb10ffdc2be..903d8dc0865 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/ConfigGenerator.java @@ -7,6 +7,7 @@ import com.yahoo.config.codegen.LeafCNode.EnumLeaf; import com.yahoo.config.codegen.LeafCNode.FileLeaf; import com.yahoo.config.codegen.LeafCNode.IntegerLeaf; import com.yahoo.config.codegen.LeafCNode.LongLeaf; +import com.yahoo.config.codegen.LeafCNode.OptionalPathLeaf; import com.yahoo.config.codegen.LeafCNode.PathLeaf; import com.yahoo.config.codegen.LeafCNode.ReferenceLeaf; import com.yahoo.config.codegen.LeafCNode.StringLeaf; @@ -165,6 +166,8 @@ public class ConfigGenerator { return name + " = LeafNodeVector.createFileNodeVector(builder." + name + ");"; } else if (child instanceof PathLeaf && isArray) { return name + " = LeafNodeVector.createPathNodeVector(builder." + name + ");"; + } else if (child instanceof OptionalPathLeaf && isArray) { + return name + " = LeafNodeVector.createOptionalPathNodeVector(builder." + name + ");"; } else if (child instanceof UrlLeaf && isArray) { return name + " = LeafNodeVector.createUrlNodeVector(builder." + name + ");"; } else if (child instanceof ModelLeaf && isArray) { @@ -175,6 +178,8 @@ public class ConfigGenerator { return name + " = LeafNodeMaps.asFileNodeMap(builder." + name + ");"; } else if (child instanceof PathLeaf && isMap) { return name + " = LeafNodeMaps.asPathNodeMap(builder." + name + ");"; + } else if (child instanceof OptionalPathLeaf && isMap) { + return name + " = LeafNodeMaps.asOptionalPathNodeMap(builder." + name + ");"; } else if (child instanceof UrlLeaf && isMap) { return name + " = LeafNodeMaps.asUrlNodeMap(builder." + name + ");"; } else if (child instanceof ModelLeaf && isMap) { @@ -401,6 +406,8 @@ public class ConfigGenerator { return "FileNode"; } else if (node instanceof PathLeaf) { return "PathNode"; + } else if (node instanceof OptionalPathLeaf) { + return "OptionalPathNode"; } else if (node instanceof UrlLeaf) { return "UrlNode"; } else if (node instanceof ModelLeaf) { @@ -431,6 +438,8 @@ public class ConfigGenerator { return "FileReference"; } else if (node instanceof PathLeaf) { return "Path"; + } else if (node instanceof OptionalPathLeaf) { + return "Optional<Path>"; } else if (node instanceof UrlLeaf) { return "File"; } else if (node instanceof ModelLeaf) { @@ -456,6 +465,8 @@ public class ConfigGenerator { return "Integer"; } else if (rawType.toLowerCase().equals(rawType)) { return ConfiggenUtil.capitalize(rawType); + } else if (rawType.startsWith("Optional<")) { + return "Optional"; } else { return rawType; } diff --git a/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java b/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java index 385c7f1979e..d6bffe349a8 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/DefLine.java @@ -7,6 +7,7 @@ import java.util.regex.Pattern; public class DefLine { private final static Pattern defaultPattern = Pattern.compile("^\\s*default\\s*=\\s*(\\S+)"); + private final static Pattern optionalPattern = Pattern.compile("^\\s*optional\\s*"); private final static Pattern rangePattern = Pattern.compile("^\\s*range\\s*=\\s*([\\(\\[].*?[\\)\\]])"); private final static Pattern restartPattern = Pattern.compile("^\\s*restart\\s*"); private final static Pattern wordPattern = Pattern.compile("\\S+"); @@ -21,6 +22,7 @@ public class DefLine { private final Type type = new Type(); private DefaultValue defaultValue = null; + private boolean optional = false; private String range = null; private boolean restart = false; @@ -74,6 +76,9 @@ public class DefLine { } public Type getType() { + if (optional && type.name.equals("path")) + type.name = "optionalPath"; + return type; } @@ -89,6 +94,8 @@ public class DefLine { return enumArray; } + public boolean isOptional() { return optional; } + /** * Special function that searches through s and returns the index * of the first occurrence of " that is not escaped. @@ -114,6 +121,7 @@ public class DefLine { private int parseOptions(CharSequence string) { Matcher defaultNullMatcher = defaultNullPattern.matcher(string); Matcher defaultMatcher = defaultPattern.matcher(string); + Matcher optionalMatcher = optionalPattern.matcher(string); Matcher rangeMatcher = rangePattern.matcher(string); Matcher restartMatcher = restartPattern.matcher(string); @@ -133,6 +141,12 @@ public class DefLine { defaultValue = new DefaultValue(deflt, type); } return defaultMatcher.end(); + } else if (optionalMatcher.find()) { + if ( ! type.name.equals("path")) + throw new IllegalArgumentException("optional can only be used for 'path'"); + optional = true; + type.name = "optionalPath"; + return optionalMatcher.end(); } else if (rangeMatcher.find()) { range = rangeMatcher.group(1); return rangeMatcher.end(); diff --git a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java index afd6acfbabf..c2470b0c703 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/LeafCNode.java @@ -26,6 +26,7 @@ public abstract class LeafCNode extends CNode { case "reference" -> new ReferenceLeaf(parent, name); case "file" -> new FileLeaf(parent, name); case "path" -> new PathLeaf(parent, name); + case "optionalPath" -> new OptionalPathLeaf(parent, name); case "enum" -> new EnumLeaf(parent, name, type.enumArray); case "url" -> new UrlLeaf(parent, name); case "model" -> new ModelLeaf(parent, name); @@ -217,6 +218,17 @@ public abstract class LeafCNode extends CNode { } } + public static class OptionalPathLeaf extends NoClassLeafCNode { + OptionalPathLeaf(InnerCNode parent, String name) { + super(parent, name); + } + + @Override + public String getType() { + return "optionalPath"; + } + } + public static class UrlLeaf extends NoClassLeafCNode { UrlLeaf(InnerCNode parent, String name) { super(parent, name); diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java index 0e2f6cc4d05..bb6b8eb64b4 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/DefLineParsingTest.java @@ -1,6 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.config.codegen; +import java.util.Optional; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -246,4 +247,24 @@ public class DefLineParsingTest { assertTrue(r1.getRestart()); } + @Test + void testParseOptionalPathWithDefault() { + DefLine l = new DefLine("pathWithDef path optional"); + + assertEquals("pathWithDef", l.getName()); + assertNull(l.getDefault()); + assertTrue(l.isOptional()); + assertEquals("optionalPath", l.getType().getName()); + } + + @Test + void testParsPathWithDefault() { + DefLine l = new DefLine("pathWithDef path"); + + assertEquals("pathWithDef", l.getName()); + assertNull(l.getDefault()); + assertFalse(l.isOptional()); + assertEquals("path", l.getType().getName()); + } + } diff --git a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java index 45d1f21763c..e5227282c05 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/DefParserTest.java @@ -28,7 +28,7 @@ public class DefParserTest { CNode root = new DefParser("test", new FileReader(defFile)).getTree(); assertNotNull(root); CNode[] children = root.getChildren(); - assertEquals(37, children.length); + assertEquals(38, children.length); int numGrandChildren = 0; int numGreatGrandChildren = 0; @@ -70,7 +70,7 @@ public class DefParserTest { void testMd5Sum() throws IOException { File defFile = new File(DEF_NAME); CNode root = new DefParser("test", new FileReader(defFile)).getTree(); - assertEquals("0501f9e2c4ecc8c283e100e0b1178ca4", root.defMd5); + assertEquals("ee37973499305fde315da46256e64b2e", root.defMd5); } @Test diff --git a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java index 428576e340f..c3145c03fff 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/JavaClassBuilderTest.java @@ -120,7 +120,7 @@ public class JavaClassBuilderTest { } for (int i = 0; i < referenceClassLines.size(); i++) { if (configClassLines.length <= i) - fail("Missing lines i generated config class. First missing line:\n" + referenceClassLines.get(i)); + fail("Missing lines in generated config class. First missing line:\n" + referenceClassLines.get(i)); assertEquals(referenceClassLines.get(i), configClassLines[i], "Line " + i); } } diff --git a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java index 57b3ed962eb..18608102ffa 100644 --- a/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java +++ b/configgen/src/test/java/com/yahoo/config/codegen/NormalizedDefinitionTest.java @@ -70,7 +70,7 @@ public class NormalizedDefinitionTest { } assertNotNull(out); - assertEquals(75, out.size()); + assertEquals(76, out.size()); assertNotNull(fileReader); fileReader.close(); diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference index b7a79f663e7..79508b3a25f 100644 --- a/configgen/src/test/resources/allfeatures.reference +++ b/configgen/src/test/resources/allfeatures.reference @@ -35,7 +35,7 @@ import com.yahoo.config.*; */ public final class AllfeaturesConfig extends ConfigInstance { - public final static String CONFIG_DEF_MD5 = "0501f9e2c4ecc8c283e100e0b1178ca4"; + public final static String CONFIG_DEF_MD5 = "ee37973499305fde315da46256e64b2e"; public final static String CONFIG_DEF_NAME = "allfeatures"; public final static String CONFIG_DEF_NAMESPACE = "configgen"; public final static String[] CONFIG_DEF_SCHEMA = { @@ -56,6 +56,7 @@ public final class AllfeaturesConfig extends ConfigInstance { "refwithdef reference default=\":parent:\"", "fileVal file", "pathVal path", + "optionalPathVal path optional", "urlVal url", "modelVal model", "boolarr[] bool", @@ -130,6 +131,7 @@ public final class AllfeaturesConfig extends ConfigInstance { private String refwithdef = null; private String fileVal = null; private FileReference pathVal = null; + private Optional<FileReference> optionalPathVal = Optional.empty(); private UrlReference urlVal = null; private ModelReference modelVal = null; public List<Boolean> boolarr = new ArrayList<>(); @@ -171,6 +173,7 @@ public final class AllfeaturesConfig extends ConfigInstance { refwithdef(config.refwithdef()); fileVal(config.fileVal().value()); pathVal(config.pathVal.getFileReference()); + optionalPathVal(config.optionalPathVal.getFileReference()); urlVal(config.urlVal.getUrlReference()); modelVal(config.modelVal.getModelReference()); boolarr(config.boolarr()); @@ -231,6 +234,8 @@ public final class AllfeaturesConfig extends ConfigInstance { fileVal(__superior.fileVal); if (__superior.pathVal != null) pathVal(__superior.pathVal); + if (__superior.optionalPathVal != null) + optionalPathVal(__superior.optionalPathVal); if (__superior.urlVal != null) urlVal(__superior.urlVal); if (__superior.modelVal != null) @@ -412,6 +417,17 @@ public final class AllfeaturesConfig extends ConfigInstance { } + public Builder optionalPathVal(Optional<FileReference> __value) { + if (__value == null) throw new IllegalArgumentException("Null value is not allowed."); + optionalPathVal = __value; + __uninitialized.remove("optionalPathVal"); + return this; + } + + private Builder optionalPathVal(FileReference __value) { + return optionalPathVal(Optional.of(__value)); + } + public Builder urlVal(UrlReference __value) { if (__value == null) throw new IllegalArgumentException("Null value is not allowed."); urlVal = __value; @@ -759,6 +775,7 @@ public final class AllfeaturesConfig extends ConfigInstance { private final ReferenceNode refwithdef; private final FileNode fileVal; private final PathNode pathVal; + private final OptionalPathNode optionalPathVal; private final UrlNode urlVal; private final ModelNode modelVal; private final LeafNodeVector<Boolean, BooleanNode> boolarr; @@ -822,6 +839,8 @@ public final class AllfeaturesConfig extends ConfigInstance { new FileNode() : new FileNode(builder.fileVal); pathVal = (builder.pathVal == null) ? new PathNode() : new PathNode(builder.pathVal); + optionalPathVal = (builder.optionalPathVal == null) ? + new OptionalPathNode() : new OptionalPathNode(builder.optionalPathVal); urlVal = (builder.urlVal == null) ? new UrlNode() : new UrlNode(builder.urlVal); modelVal = (builder.modelVal == null) ? @@ -960,6 +979,13 @@ public final class AllfeaturesConfig extends ConfigInstance { } /** + * @return allfeatures.optionalPathVal + */ + public Optional<Path> optionalPathVal() { + return optionalPathVal.value(); + } + + /** * @return allfeatures.urlVal */ public File urlVal() { diff --git a/configgen/src/test/resources/configgen.allfeatures.def b/configgen/src/test/resources/configgen.allfeatures.def index 1f93e29b73b..eee39dc18f3 100644 --- a/configgen/src/test/resources/configgen.allfeatures.def +++ b/configgen/src/test/resources/configgen.allfeatures.def @@ -39,6 +39,7 @@ refVal reference refwithdef reference default=":parent:" fileVal file pathVal path +optionalPathVal path optional urlVal url modelVal model |