summaryrefslogtreecommitdiffstats
path: root/configgen/src/main/scala/com
diff options
context:
space:
mode:
Diffstat (limited to 'configgen/src/main/scala/com')
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala350
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala423
-rw-r--r--configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala186
3 files changed, 0 insertions, 959 deletions
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala b/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala
deleted file mode 100644
index 4f6f310e32e..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/BuilderGenerator.scala
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-import com.yahoo.config.codegen.ReservedWords.{INTERNAL_PREFIX => InternalPrefix}
-import JavaClassBuilder.{Indentation, createUniqueSymbol}
-import ConfigGenerator.{indentCode, nodeClass, userDataType, boxedDataType}
-import com.yahoo.config.codegen.LeafCNode._
-
-/**
- * @author gjoranv
- */
-
-object BuilderGenerator {
-
- def getBuilder(node: InnerCNode): String = {
- getDeclaration(node) + "\n" +
- indentCode(Indentation,
- getUninitializedScalars(node) + "\n\n" +
- node.getChildren.map(getBuilderFieldDefinition).mkString("\n") + "\n\n" +
- getBuilderConstructors(node, nodeClass(node)) + "\n\n" +
- getOverrideMethod(node) + "\n\n" +
- getBuilderSetters(node) + "\n" +
- getSpecialRootBuilderCode(node)
- ) +
- "}"
- }
-
- private def getDeclaration(node: InnerCNode) = {
- def getInterfaces =
- if (node.getParent == null) "implements ConfigInstance.Builder"
- else "implements ConfigBuilder"
-
- "public static class Builder " + getInterfaces + " {"
- }
-
- private def getSpecialRootBuilderCode(node: InnerCNode) = {
- if (node.getParent == null) "\n" + getDispatchCode(node) + "\n"
- else ""
- }
-
- private def getDispatchCode(node: InnerCNode) = {
- // Use full path to @Override, as users are free to define an inner node called 'override'. (summarymap.def does)
- // The generated inner 'Override' class would otherwise be mistaken for the annotation.
- """
- |@java.lang.Override
- |public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {
- | if (producer instanceof Producer) {
- | ((Producer)producer).getConfig(this);
- | return true;
- | }
- | return false;
- |}
- |
- |@java.lang.Override
- |public final String getDefMd5() { return CONFIG_DEF_MD5; }
- |@java.lang.Override
- |public final String getDefName() { return CONFIG_DEF_NAME; }
- |@java.lang.Override
- |public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }
- """.stripMargin.trim
- }
-
- private def getUninitializedScalars(node: InnerCNode): String = {
- val scalarsWithoutDefault = {
- node.getChildren.collect {
- case leaf: LeafCNode if (!leaf.isArray && !leaf.isMap && leaf.getDefaultValue == null) =>
- "\"" + leaf.getName + "\""
- }
- }
-
- val uninitializedList =
- if (scalarsWithoutDefault.size > 0)
- "Arrays.asList(\n" + indentCode(Indentation, scalarsWithoutDefault.mkString("",",\n","\n)"))
- else
- ""
-
- "private Set<String> " + InternalPrefix + "uninitialized = new HashSet<String>(" + uninitializedList + ");"
- }
-
- private def getBuilderFieldDefinition(node: CNode): String = {
-
- (node match {
- case array if node.isArray =>
- "public List<%s> %s = new ArrayList<>()".format(builderType(array), array.getName)
- case map if node.isMap =>
- "public Map<String, %s> %s = new LinkedHashMap<>()".format(builderType(map), map.getName)
- case struct: InnerCNode =>
- "public %s %s = new %s()".format(builderType(struct), struct.getName, builderType(struct))
- case scalar : LeafCNode =>
- "private " + boxedBuilderType(scalar) + " " + scalar.getName + " = null"
- }) + ";"
- }
-
- private def getBuilderSetters(node: CNode): String = {
- val children: Array[CNode] = node.getChildren
-
- def structSetter(node: InnerCNode) = {
- <code>
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}builder) {{
- | {node.getName} = {InternalPrefix}builder;
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def innerArraySetters(node: InnerCNode) = {
- <code>
- |/**
- | * Add the given builder to this builder's list of {nodeClass(node)} builders
- | * @param {InternalPrefix}builder a builder
- | * @return this builder
- | */
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}builder) {{
- | {node.getName}.add({InternalPrefix}builder);
- | return this;
- |}}
- |
- |/**
- | * Set the given list as this builder's list of {nodeClass(node)} builders
- | * @param __builders a list of builders
- | * @return this builder
- | */
- |public Builder {node.getName}(List&lt;{builderType(node)}&gt; __builders) {{
- | {node.getName} = __builders;
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def leafArraySetters(node: LeafCNode) = {
- val setters =
- <code>
- |public Builder {node.getName}({builderType(node)} {InternalPrefix}value) {{
- | {node.getName}.add({InternalPrefix}value);
- | return this;
- |}}
- |
- |public Builder {node.getName}(Collection&lt;{builderType(node)}&gt; {InternalPrefix}values) {{
- | {node.getName}.addAll({InternalPrefix}values);
- | return this;
- |}}
- </code>.text.stripMargin.trim
-
- val privateSetter =
- if (builderType(node) == "String" || builderType(node) == "FileReference")
- ""
- else
- "\n\n" +
- <code>
- |
- |
- |private Builder {node.getName}(String {InternalPrefix}value) {{
- | return {node.getName}({builderType(node)}.valueOf({InternalPrefix}value));
- |}}
- </code>.text.stripMargin.trim
-
- setters + privateSetter
- }
-
- def innerMapSetters(node: CNode) = {
- <code>
- |public Builder {node.getName}(String {InternalPrefix}key, {builderType(node)} {InternalPrefix}value) {{
- | {node.getName}.put({InternalPrefix}key, {InternalPrefix}value);
- | return this;
- |}}
- |
- |public Builder {node.getName}(Map&lt;String, {builderType(node)}&gt; {InternalPrefix}values) {{
- | {node.getName}.putAll({InternalPrefix}values);
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- def leafMapSetters(node: LeafCNode) = {
- val privateSetter =
- if (builderType(node) == "String" || builderType(node) == "FileReference")
- ""
- else
- "\n\n" +
- <code>
- |
- |
- |private Builder {node.getName}(String {InternalPrefix}key, String {InternalPrefix}value) {{
- | return {node.getName}({InternalPrefix}key, {builderType(node)}.valueOf({InternalPrefix}value));
- |}}
- </code>.text.stripMargin.trim
-
- innerMapSetters(node) + privateSetter
- }
-
- def scalarSetters(node: LeafCNode): String = {
- val name = node.getName
-
- val signalInitialized =
- if (node.getDefaultValue == null) InternalPrefix + "uninitialized.remove(\"" + name + "\");\n"
- else ""
-
- val stringSetter =
- builderType(node) match {
- case "String" => ""
- case "FileReference" => ""
- case _ =>
- """|
- |private Builder %s(String %svalue) {
- | return %s(%s.valueOf(%svalue));
- |}""".stripMargin.format(name, InternalPrefix,
- name, boxedDataType(node), InternalPrefix)
- }
-
- def getNullGuard = {
- if (builderType(node) != boxedBuilderType(node))
- ""
- else
- "\n" + "if (%svalue == null) throw new IllegalArgumentException(\"Null value is not allowed.\");"
- .format(InternalPrefix)
- }
-
- // TODO: check if 2.9.2 allows string to start with a newline
- """|public Builder %s(%s %svalue) {%s
- | %s = %svalue;
- | %s
- """.stripMargin.format(name, builderType(node), InternalPrefix, getNullGuard,
- name, InternalPrefix,
- signalInitialized).trim +
- "\n return this;" + "\n}\n" +
- stringSetter
- }
-
- (children collect {
- case innerArray: InnerCNode if innerArray.isArray => innerArraySetters(innerArray)
- case innerMap: InnerCNode if innerMap.isMap => innerMapSetters(innerMap)
- case leafArray: LeafCNode if leafArray.isArray => leafArraySetters(leafArray)
- case leafMap: LeafCNode if leafMap.isMap => leafMapSetters(leafMap)
- case struct: InnerCNode => structSetter(struct)
- case scalar: LeafCNode => scalarSetters(scalar)
- } ).mkString("\n\n")
- }
-
- private def getBuilderConstructors(node: CNode, className: String): String = {
- def setBuilderValueFromConfig(child: CNode) = {
- val name = child.getName
- val isArray = child.isArray
- val isMap = child.isMap
-
- child match {
- case fileArray: FileLeaf if isArray => name + "(" + userDataType(fileArray) + ".toValues(config." + name + "()));"
- case fileMap: FileLeaf if isMap => name + "(" + userDataType(fileMap) + ".toValueMap(config." + name + "()));"
- case file: FileLeaf => name + "(config." + name + "().value());"
- case pathArray: PathLeaf if isArray => name + "(" + nodeClass(pathArray) + ".toFileReferences(config." + name + "));"
- case pathMap: PathLeaf if isMap => name + "(" + nodeClass(pathMap) + ".toFileReferenceMap(config." + name + "));"
- case path: PathLeaf => name + "(config." + name + ".getFileReference());"
- case leaf: LeafCNode => name + "(config." + name + "());"
- case innerArray: InnerCNode if isArray => setInnerArrayBuildersFromConfig(innerArray)
- case innerMap: InnerCNode if isMap => setInnerMapBuildersFromConfig(innerMap)
- case struct => name + "(new " + builderType(struct) + "(config." + name + "()));"
- }
- }
-
- def setInnerArrayBuildersFromConfig(innerArr: InnerCNode) = {
- val elemName = createUniqueSymbol(node, innerArr.getName)
- <code>
- |for ({userDataType(innerArr)} {elemName} : config.{innerArr.getName}()) {{
- | {innerArr.getName}(new {builderType(innerArr)}({elemName}));
- |}}
- </code>.text.stripMargin.trim
- }
-
- def setInnerMapBuildersFromConfig(innerMap: InnerCNode) = {
- val entryName = InternalPrefix + "entry"
- <code>
- |for (Map.Entry&lt;String, {userDataType(innerMap)}&gt; {entryName} : config.{innerMap.getName}().entrySet()) {{
- | {innerMap.getName}({entryName}.getKey(), new {userDataType(innerMap)}.Builder({entryName}.getValue()));
- |}}
- </code>.text.stripMargin.trim
- }
-
- <code>
- |public Builder() {{ }}
- |
- |public Builder({className} config) {{
- |{indentCode(Indentation, node.getChildren.map(setBuilderValueFromConfig).mkString("\n"))}
- |}}
- </code>.text.stripMargin.trim
- }
-
- def arrayOverride(name: String, superior: String): String = {
- Indentation + name + ".addAll(" + superior + "." + name + ");"
- }
-
- private def getOverrideMethod(node:CNode): String = {
- val method = "override"
- val superior = InternalPrefix + "superior"
-
- def callSetter(name: String): String = {
- name + "(" + superior + "." + name + ");"
- }
- def overrideBuilderValue(child: CNode) = {
- val name = child.getName
- child match {
- case leafArray: CNode if (child.isArray) =>
- conditionStatement(child) + "\n" + arrayOverride(name, superior)
- case struct: InnerCNode if !(child.isArray || child.isMap) =>
- name + "(" + name + "." + method + "(" + superior + "." + name + "));"
- case map: CNode if child.isMap =>
- callSetter(name)
- case _ =>
- conditionStatement(child) + "\n" +
- Indentation + callSetter(name)
- }
- }
-
- def conditionStatement(child: CNode) = {
- val name = child.getName
- val isArray = child.isArray
- val isMap = child.isMap
- child match {
- case _ if isArray => "if (!" + superior + "." + name + ".isEmpty())"
- case _ if isMap => ""
- case scalar: LeafCNode => "if (" + superior + "." + name + " != null)"
- case struct => ""
- }
- }
-
- <code>
- |private Builder {method}(Builder {superior}) {{
- |{indentCode(Indentation, node.getChildren.map(overrideBuilderValue).mkString("\n"))}
- | return this;
- |}}
- </code>.text.stripMargin.trim
- }
-
- private def builderType(node: CNode): String = {
- node match {
- case inner: InnerCNode => boxedDataType(node) + ".Builder"
- case file: FileLeaf => "String"
- case path: PathLeaf => "FileReference"
- case leafArray: LeafCNode if (node.isArray || node.isMap) => boxedDataType(node)
- case _ => userDataType(node)
- }
- }
-
- private def boxedBuilderType(node: LeafCNode): String = {
- node match {
- case file: FileLeaf => "String"
- case path: PathLeaf => "FileReference"
- case _ => boxedDataType(node)
- }
- }
-
-}
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala b/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala
deleted file mode 100644
index 38306a03575..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/ConfigGenerator.scala
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-
-import com.yahoo.config.codegen.BuilderGenerator.getBuilder
-import com.yahoo.config.codegen.JavaClassBuilder.Indentation
-import com.yahoo.config.codegen.LeafCNode._
-import com.yahoo.config.codegen.ReservedWords.{INTERNAL_PREFIX => InternalPrefix}
-
-/**
- * @author gjoranv
- * @author tonytv
- */
-// TODO: don't take indent as method param - the caller should indent
-object ConfigGenerator {
-
- def generateContent(indent: String, node: InnerCNode, isOuter: Boolean = true): String = {
- val children: Array[CNode] = node.getChildren
-
- def generateCodeForChildren: String = {
- (children collect {
- case enum: EnumLeaf => getEnumCode(enum, "") + "\n"
- case inner: InnerCNode => getInnerDefinition(inner, indent) + "\n"
- } ).mkString("\n")
- }
-
- def getInnerDefinition(inner: InnerCNode, indent: String) = {
- <code>
- |{getClassDoc(inner, indent)}
- |{getClassDeclaration(inner)}
- |{generateContent(indent, inner, false)}
- </code>.text.stripMargin.trim + "\n}"
- }
-
- def getClassDeclaration(node: CNode): String = {
- "public final static class " + nodeClass(node)+ " extends InnerNode { " + "\n"
- }
-
- def getFieldDefinition(node: CNode): String = {
- node.getCommentBlock("//") + "private final " +
- (node match {
- case _: LeafCNode if node.isArray =>
- "LeafNodeVector<%s, %s> %s;".format(boxedDataType(node), nodeClass(node), node.getName)
- case _: InnerCNode if node.isArray =>
- "InnerNodeVector<%s> %s;".format(nodeClass(node), node.getName)
- case _ if node.isMap =>
- "Map<String, %s> %s;".format(nodeClass(node), node.getName)
- case _ =>
- "%s %s;".format(nodeClass(node), node.getName)
- })
- }
-
- def getStaticMethods = {
- if (node.isArray) getStaticMethodsForInnerArray(node) + "\n\n"
- else if (node.isMap) getStaticMethodsForInnerMap(node) + "\n\n"
- else ""
- }
-
- def getContainsFieldsFlaggedWithRestart(node: CNode): String = {
- if (isOuter) {
- """
- |private static boolean containsFieldsFlaggedWithRestart() {
- | return %b;
- |}
- """.stripMargin.trim.format(node.needRestart) + "\n\n"
- } else ""
- }
-
- indentCode(indent,
- getBuilder(node) + "\n\n" +
- children.map(getFieldDefinition).mkString("\n") + "\n\n" +
- getConstructors(node) + "\n\n" +
- getAccessors(children) + "\n\n" +
- getGetChangesRequiringRestart(node) + "\n\n" +
- getContainsFieldsFlaggedWithRestart(node) +
- getStaticMethods +
- generateCodeForChildren
- )
- }
-
- private def getGetChangesRequiringRestart(node: InnerCNode): String = {
- def quotedComment(node: CNode): String = {
- node.getComment.replace("\n", "\\n").replace("\"", "\\\"")
- }
-
- def getComparison(node: CNode): String = node match {
- case inner: InnerCNode if inner.isArray =>
- <code>
- | changes.compareArray(this.{inner.getName}, newConfig.{inner.getName}, "{inner.getName}", "{quotedComment(inner)}",
- | (a,b) -> (({nodeClass(inner)})a).getChangesRequiringRestart(({nodeClass(inner)})b));
- </code>.text.stripMargin.trim
- case inner: InnerCNode if inner.isMap =>
- <code>
- | changes.compareMap(this.{inner.getName}, newConfig.{inner.getName}, "{inner.getName}", "{quotedComment(inner)}",
- | (a,b) -> (({nodeClass(inner)})a).getChangesRequiringRestart(({nodeClass(inner)})b));
- </code>.text.stripMargin.trim
- case inner: InnerCNode =>
- <code>
- | changes.mergeChanges("{inner.getName}", this.{inner.getName}.getChangesRequiringRestart(newConfig.{inner.getName}));
- </code>.text.stripMargin.trim
- case node: CNode if node.isArray =>
- <code>
- | changes.compareArray(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}",
- | (a,b) -> new ChangesRequiringRestart("{node.getName}").compare(a,b,"","{quotedComment(node)}"));
- </code>.text.stripMargin.trim
- case node: CNode if node.isMap =>
- <code>
- | changes.compareMap(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}",
- | (a,b) -> new ChangesRequiringRestart("{node.getName}").compare(a,b,"","{quotedComment(node)}"));
- </code>.text.stripMargin.trim
- case node: CNode =>
- <code>
- | changes.compare(this.{node.getName}, newConfig.{node.getName}, "{node.getName}", "{quotedComment(node)}");
- </code>.text.stripMargin.trim
- }
-
- val comparisons =
- for {
- c <- node.getChildren if c.needRestart
- } yield "\n " + getComparison(c)
-
- <code>
- |private ChangesRequiringRestart getChangesRequiringRestart({nodeClass(node)} newConfig) {{
- | ChangesRequiringRestart changes = new ChangesRequiringRestart("{node.getName}");{comparisons.mkString("")}
- | return changes;
- |}}
- </code>.text.stripMargin.trim
- }
-
-
- private def scalarDefault(scalar: LeafCNode): String = {
- scalar match {
- case _ if scalar.getDefaultValue == null => ""
- case enumWithNullDefault: EnumLeaf if enumWithNullDefault.getDefaultValue.getValue == null => ""
- case enum: EnumLeaf => nodeClass(enum) + "." + enum.getDefaultValue.getStringRepresentation
- case long: LongLeaf => long.getDefaultValue.getStringRepresentation + "L"
- case double: DoubleLeaf => double.getDefaultValue.getStringRepresentation + "D"
- case _ => scalar.getDefaultValue.getStringRepresentation
- }
- }
-
- private def getConstructors(inner: InnerCNode) = {
-
- def assignFromBuilder(child: CNode) = {
- val name = child.getName
- val className = nodeClass(child)
- val dataType = boxedDataType(child)
- val isArray = child.isArray
- val isMap = child.isMap
-
- def assignIfInitialized(leaf: LeafCNode) = {
- <code>
- |{name} = (builder.{name} == null) ?
- | new {className}({scalarDefault(leaf)}) : new {className}(builder.{name});
- </code>.text.stripMargin.trim
- }
-
- child match {
- case fileArray: FileLeaf if isArray =>
- name + " = LeafNodeVector.createFileNodeVector(builder."+ name +");"
- case pathArray: PathLeaf if isArray =>
- name + " = LeafNodeVector.createPathNodeVector(builder."+ name +");"
- case leafArray: LeafCNode if isArray =>
- name + " = new LeafNodeVector<>(builder."+ name +", new " + className + "());"
- case fileMap: LeafCNode if isMap && child.isInstanceOf[FileLeaf] =>
- name + " = LeafNodeMaps.asFileNodeMap(builder."+ name +");"
- case pathMap: LeafCNode if isMap && child.isInstanceOf[PathLeaf] =>
- name + " = LeafNodeMaps.asPathNodeMap(builder."+ name +");"
- case leafMap: LeafCNode if isMap =>
- name + " = LeafNodeMaps.asNodeMap(builder."+ name +", new " + className + "());"
- case innerArray: InnerCNode if isArray =>
- name + " = " + className + ".createVector(builder." + name + ");"
- case innerMap: InnerCNode if isMap =>
- name + " = " + className + ".createMap(builder." + name + ");"
- case struct: InnerCNode =>
- name + " = new " + className + "(builder." + name + ", throwIfUninitialized);"
- case leaf: LeafCNode =>
- assignIfInitialized(leaf)
- }
- }
-
- // TODO: merge these two constructors into one when the config library uses builders to set values from payload.
- <code>
- |public {nodeClass(inner)}(Builder builder) {{
- | this(builder, true);
- |}}
- |
- |private {nodeClass(inner)}(Builder builder, boolean throwIfUninitialized) {{
- | if (throwIfUninitialized &amp;&amp; ! builder.{InternalPrefix}uninitialized.isEmpty())
- | throw new IllegalArgumentException("The following builder parameters for " +
- | "{inner.getFullName} must be initialized: " + builder.{InternalPrefix}uninitialized);
- |
- |{indentCode(Indentation, inner.getChildren.map(assignFromBuilder).mkString("\n"))}
- |}}
- </code>.text.stripMargin.trim
- }
-
- private def getAccessors(children: Array[CNode]): String = {
-
- def getAccessorCode(indent: String, node: CNode): String = {
- indentCode(indent,
- if (node.isArray)
- accessorsForArray(node)
- else if (node.isMap)
- accessorsForMap(node)
- else
- accessorForStructOrScalar(node))
- }
-
- def valueAccessor(node: CNode) = node match {
- case leaf: LeafCNode => ".value()"
- case inner => ""
- }
-
- def listAccessor(node: CNode) = node match {
- case leaf: LeafCNode => "%s.asList()".format(leaf.getName)
- case inner => inner.getName
- }
-
- def mapAccessor(node: CNode) = node match {
- case leaf: LeafCNode => "LeafNodeMaps.asValueMap(%s)".format(leaf.getName)
- case inner => "Collections.unmodifiableMap(%s)".format(inner.getName)
- }
-
- def accessorsForArray(node: CNode): String = {
- val name = node.getName
- val fullName = node.getFullName
- <code>
- |/**
- | * @return {fullName}
- | */
- |public List&lt;{boxedDataType(node)}&gt; {name}() {{
- | return {listAccessor(node)};
- |}}
- |
- |/**
- | * @param i the index of the value to return
- | * @return {fullName}
- | */
- |public {userDataType(node)} {name}(int i) {{
- | return {name}.get(i){valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- def accessorsForMap(node: CNode): String = {
- val name = node.getName
- val fullName = node.getFullName
- <code>
- |/**
- | * @return {fullName}
- | */
- |public Map&lt;String, {boxedDataType(node)}&gt; {name}() {{
- | return {mapAccessor(node)};
- |}}
- |
- |/**
- | * @param key the key of the value to return
- | * @return {fullName}
- | */
- |public {userDataType(node)} {name}(String key) {{
- | return {name}.get(key){valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- def accessorForStructOrScalar(node: CNode): String = {
- <code>
- |/**
- | * @return {node.getFullName}
- | */
- |public {userDataType(node)} {node.getName}() {{
- | return {node.getName}{valueAccessor(node)};
- |}}
- </code>.text.stripMargin.trim
- }
-
- val accessors =
- for {
- c <- children
- accessor = getAccessorCode("", c)
- if (accessor.length > 0)
- } yield (accessor + "\n")
- accessors.mkString("\n").trim
- }
-
- private def getStaticMethodsForInnerArray(inner: InnerCNode) = {
- """
- |private static InnerNodeVector<%s> createVector(List<Builder> builders) {
- | List<%s> elems = new ArrayList<>();
- | for (Builder b : builders) {
- | elems.add(new %s(b));
- | }
- | return new InnerNodeVector<%s>(elems);
- |}
- """.stripMargin.format(List.fill(5)(nodeClass(inner)): _*).trim
- }
-
- private def getStaticMethodsForInnerMap(inner: InnerCNode) = {
- """
- |private static Map<String, %s> createMap(Map<String, Builder> builders) {
- | Map<String, %s> ret = new LinkedHashMap<>();
- | for(String key : builders.keySet()) {
- | ret.put(key, new %s(builders.get(key)));
- | }
- | return Collections.unmodifiableMap(ret);
- |}
- """.stripMargin.format(List.fill(3)(nodeClass(inner)): _*).trim
- }
-
- private def getEnumCode(enum: EnumLeaf, indent: String): String = {
-
- def getEnumValues(enum: EnumLeaf): String = {
- val enumValues =
- for (value <- enum.getLegalValues) yield
- """ public final static Enum %s = Enum.%s;""".format(value, value)
- enumValues.mkString("\n")
- }
-
- // TODO: try to rewrite to xml
- val code =
- """
- |%s
- |public final static class %s extends EnumNode<%s> {
-
- | public %s(){
- | this.value = null;
- | }
-
- | public %s(Enum enumValue) {
- | super(enumValue != null);
- | this.value = enumValue;
- | }
-
- | public enum Enum {%s}
- |%s
-
- | @Override
- | protected boolean doSetValue(@NonNull String name) {
- | try {
- | value = Enum.valueOf(name);
- | return true;
- | } catch (IllegalArgumentException e) {
- | }
- | return false;
- | }
- |}
- |"""
- .stripMargin.format(getClassDoc(enum, indent),
- nodeClass(enum),
- nodeClass(enum)+".Enum",
- nodeClass(enum),
- nodeClass(enum),
- enum.getLegalValues.mkString(", "),
- getEnumValues(enum))
-
- indentCode(indent, code).trim
- }
-
- def getClassDoc(node: CNode, indent: String): String = {
- val header = "/**\n" + " * This class represents " + node.getFullName
- val nodeComment = node.getCommentBlock(" *") match {
- case "" => ""
- case s => "\n *\n" + s.stripLineEnd // TODO: strip trailing \n in CNode.getCommentBlock
- }
- header + nodeComment + "\n */"
- }
-
- def indentCode(indent: String, code: String): String = {
- val indentedLines =
- for (s <- code.split("\n", -1)) yield
- if (s.length() > 0) (indent + s) else s
- indentedLines.mkString("\n")
- }
-
- /**
- * @return the name of the class that is generated by this node.
- */
- def nodeClass(node: CNode): String = {
- node match {
- case emptyName: CNode if node.getName.length == 0 =>
- throw new CodegenRuntimeException("Node with empty name, under parent " + emptyName.getParent.getName)
- case root: InnerCNode if root.getParent == null => ConfiggenUtil.createClassName(root.getName)
- case b: BooleanLeaf => "BooleanNode"
- case d: DoubleLeaf => "DoubleNode"
- case f: FileLeaf => "FileNode"
- case p: PathLeaf => "PathNode"
- case i: IntegerLeaf => "IntegerNode"
- case l: LongLeaf => "LongNode"
- case r: ReferenceLeaf => "ReferenceNode"
- case s: StringLeaf => "StringNode"
- case _ => node.getName.capitalize
- }
- }
-
- def userDataType(node: CNode): String = {
- node match {
- case inner: InnerCNode => nodeClass(node)
- case enum: EnumLeaf => nodeClass(enum) + ".Enum"
- case b: BooleanLeaf => "boolean"
- case d: DoubleLeaf => "double"
- case f: FileLeaf => "FileReference"
- case p: PathLeaf => "Path"
- case i: IntegerLeaf => "int"
- case l: LongLeaf => "long"
- case s: StringLeaf => "String"
- }
- }
-
- /**
- * @return the boxed java data type, e.g. Integer for int
- */
- def boxedDataType(node: CNode): String = {
- val rawType = userDataType(node)
-
- rawType match {
- case "int" => "Integer"
- case _ if rawType == rawType.toLowerCase => rawType.capitalize
- case _ => rawType
- }
- }
-
-}
diff --git a/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala b/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala
deleted file mode 100644
index e03a6d3d04b..00000000000
--- a/configgen/src/main/scala/com/yahoo/config/codegen/JavaClassBuilder.scala
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.config.codegen
-
-import java.io.{File, FileNotFoundException, FileOutputStream, PrintStream}
-
-import com.yahoo.config.codegen.ConfigGenerator.indentCode
-import com.yahoo.config.codegen.ConfiggenUtil.createClassName
-import com.yahoo.config.codegen.DefParser.DEFAULT_PACKAGE_PREFIX
-
-import scala.collection.JavaConverters._
-import scala.util.Random
-/**
- * Builds one Java class based on the given CNode tree.
- *
- * @author gjoranv
- * @author tonytv
- */
-class JavaClassBuilder(
- root: InnerCNode,
- nd: NormalizedDefinition,
- destDir: File,
- rawPackagePrefix: String)
- extends ClassBuilder
-{
- import JavaClassBuilder._
-
- val packagePrefix = if (rawPackagePrefix != null) rawPackagePrefix else DEFAULT_PACKAGE_PREFIX
- val javaPackage = if (root.getPackage != null) root.getPackage else packagePrefix + root.getNamespace
- val className = createClassName(root.getName)
-
- override def createConfigClasses() {
- try {
- val outFile = new File(getDestPath(destDir, javaPackage), className + ".java")
- var out: PrintStream = null
- try {
- out = new PrintStream(new FileOutputStream(outFile))
- out.print(getConfigClass(className))
- } finally {
- if (out != null) out.close()
- }
- System.err.println(outFile.getPath + " successfully written.")
- }
- catch {
- case e: FileNotFoundException => {
- throw new CodegenRuntimeException(e)
- }
- }
- }
-
- def getConfigClass(className:String): String = {
- val ret = new StringBuilder
-
- ret.append(getHeader).append("\n\n")
- ret.append(getRootClassDeclaration(root, className)).append("\n\n")
- ret.append(indentCode(Indentation, getFrameworkCode(className))).append("\n\n")
- ret.append(ConfigGenerator.generateContent(Indentation, root)).append("\n")
- ret.append("}\n")
-
- ret.toString()
- }
-
- private def getHeader: String = {
- <code>
- |/**
- | * This file is generated from a config definition file.
- | * ------------ D O N O T E D I T ! ------------
- | */
- |
- |package {javaPackage};
- |
- |import java.util.*;
- |import java.nio.file.Path;
- |import edu.umd.cs.findbugs.annotations.NonNull;
- |{getImportFrameworkClasses(root.getNamespace)}
- </code>.text.stripMargin.trim
- }
-
- private def getImportFrameworkClasses(namespace: String): String = {
- if (namespace != CNode.DEFAULT_NAMESPACE)
- "import " + packagePrefix + CNode.DEFAULT_NAMESPACE + ".*;\n"
- else
- ""
- }
-
- // TODO: remove the extra comment line " *" if root.getCommentBlock is empty
- private def getRootClassDeclaration(root:InnerCNode, className: String): String = {
- <code>
- |/**
- | * This class represents the root node of {root.getFullName}
- | *
- |{root.getCommentBlock(" *")} */
- |public final class {className} extends ConfigInstance {{
- |
- | public final static String CONFIG_DEF_MD5 = "{root.getMd5}";
- | public final static String CONFIG_DEF_NAME = "{root.getName}";
- | public final static String CONFIG_DEF_NAMESPACE = "{root.getNamespace}";
- | public final static String CONFIG_DEF_VERSION = "{root.getVersion}";
- | public final static String[] CONFIG_DEF_SCHEMA = {{
- |{indentCode(Indentation * 2, getDefSchema)}
- | }};
- |
- | public static String getDefMd5() {{ return CONFIG_DEF_MD5; }}
- | public static String getDefName() {{ return CONFIG_DEF_NAME; }}
- | public static String getDefNamespace() {{ return CONFIG_DEF_NAMESPACE; }}
- | public static String getDefVersion() {{ return CONFIG_DEF_VERSION; }}
- </code>.text.stripMargin.trim
- }
-
- private def getDefSchema: String = {
- nd.getNormalizedContent.asScala.map { line =>
- "\"" +
- line.replace("\"", "\\\"") +
- "\""
- }.mkString(",\n")
- }
-
- private def getFrameworkCode(className: String): String = {
- getProducerBase
- }
-
- private def getProducerBase = {
- """
- |public interface Producer extends ConfigInstance.Producer {
- | void getConfig(Builder builder);
- |}
- """.stripMargin.trim
- }
-
- /**
- * @param rootDir The root directory for the destination path.
- * @param javaPackage The java package
- * @return the destination path for the generated config file, including the given rootDir.
- */
- private def getDestPath(rootDir: File, javaPackage: String): File = {
- var dir: File = rootDir
- val subDirs: Array[String] = javaPackage.split("""\.""")
- for (subDir <- subDirs) {
- dir = new File(dir, subDir)
- this.synchronized {
- if (!dir.isDirectory && !dir.mkdir) throw new CodegenRuntimeException("Could not create " + dir.getPath)
- }
- }
- dir
- }
-
-}
-
-
-object JavaClassBuilder {
-
- val Indentation = " "
-
- /**
- * Returns a name that can be safely used as a local variable in the generated config class
- * for the given node. The name will be based on the given basis string, but the basis itself is
- * not a possible return value.
- *
- * @param node The node to find a unused symbol name for.
- * @param basis The basis for the generated symbol name.
- * @return A name that is not used in the given config node.
- */
- def createUniqueSymbol(node: CNode, basis: String) = {
-
- def getCandidate(cnt: Int) = {
- if (cnt < basis.length())
- basis.substring(0, cnt)
- else
- ReservedWords.INTERNAL_PREFIX + basis + Random.nextInt().abs
- }
-
- def getUsedSymbols: Set[String] = {
- (node.getChildren map (child => child.getName)).toSet
- }
-
- // TODO: refactoring potential
- val usedSymbols = getUsedSymbols
- var count = 1
- var candidate = getCandidate(count)
- while (usedSymbols contains(candidate)) {
- count += 1
- candidate = getCandidate(count)
- }
- candidate
- }
-
-}