
com.yahoo.config.codegen.JavaClassBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of configgen Show documentation
Show all versions of configgen Show documentation
Config java code generation from defintion files for Java Vespa components.
// 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.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import static com.yahoo.config.codegen.ConfigGenerator.indentCode;
import static com.yahoo.config.codegen.ConfiggenUtil.createClassName;
import static com.yahoo.config.codegen.DefParser.DEFAULT_PACKAGE_PREFIX;
/**
* Builds one Java class based on the given CNode tree.
*
* @author gjoranv
* @author Tony Vaagenes
* @author ollivir
*/
public class JavaClassBuilder implements ClassBuilder {
static final String INDENTATION = " ";
private final InnerCNode root;
private final NormalizedDefinition nd;
private final String javaPackage;
private final String className;
private final File destDir;
public JavaClassBuilder(InnerCNode root, NormalizedDefinition nd, File destDir, String rawPackagePrefix) {
this.root = root;
this.nd = nd;
String packagePrefix = (rawPackagePrefix != null) ? rawPackagePrefix : DEFAULT_PACKAGE_PREFIX;
this.javaPackage = (root.getPackage() != null) ? root.getPackage() : packagePrefix + root.getNamespace();
this.className = createClassName(root.getName());
this.destDir = destDir;
}
@Override
public void createConfigClasses() {
try {
File outFile = new File(getDestPath(destDir, javaPackage), className + ".java");
try (PrintStream out = new PrintStream(new FileOutputStream(outFile))) {
out.print(getConfigClass(className));
}
} catch (FileNotFoundException e) {
throw new CodegenRuntimeException(e);
}
}
public String getConfigClass(String className) {
return getHeader() + "\n\n" + //
getRootClassDeclaration(root, className) + "\n\n" + //
indentCode(INDENTATION, getFrameworkCode()) + "\n\n" + //
ConfigGenerator.generateContent(INDENTATION, root, true) + "\n" + //
"}\n";
}
private String getHeader() {
return "/**\n" + //
" * This file is generated from a config definition file.\n" + //
" * ------------ D O N O T E D I T ! ------------\n" + //
" */\n" + //
"\n" + //
"package " + javaPackage + ";\n" + //
"\n" + //
"import java.util.*;\n" + //
"import java.io.File;\n" + //
"import java.nio.file.Path;\n" + //
"import com.yahoo.config.*;";
}
// TODO: remove the extra comment line " *" if root.getCommentBlock is empty
private String getRootClassDeclaration(InnerCNode root, String className) {
return "/**\n" + //
" * This class represents the root node of " + root.getFullName() + "\n" + //
" *\n" + //
"" + root.getCommentBlock(" *") + " */\n" + //
"public final class " + className + " extends ConfigInstance {\n" + //
"\n" + //
" public final static String CONFIG_DEF_MD5 = \"" + root.getMd5() + "\";\n" + //
" public final static String CONFIG_DEF_NAME = \"" + root.getName() + "\";\n" + //
" public final static String CONFIG_DEF_NAMESPACE = \"" + root.getNamespace() + "\";\n" + //
" public final static String[] CONFIG_DEF_SCHEMA = {\n" + //
"" + indentCode(INDENTATION + INDENTATION, getDefSchema()) + "\n" + //
" };\n" + //
"\n" + //
" public static String getDefMd5() { return CONFIG_DEF_MD5; }\n" + //
" public static String getDefName() { return CONFIG_DEF_NAME; }\n" + //
" public static String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }";
}
private String getDefSchema() {
return nd.getNormalizedContent().stream().map(l -> "\"" + l.replace("\"", "\\\"") + "\"").collect(Collectors.joining(",\n"));
}
private String getFrameworkCode() {
return "public interface Producer extends ConfigInstance.Producer {\n" + //
" void getConfig(Builder builder);\n" + //
"}";
}
/**
* @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 File getDestPath(File rootDir, String javaPackage) {
File dir = rootDir;
for (String subDir : javaPackage.split("\\.")) {
dir = new File(dir, subDir);
synchronized (this) {
if (!dir.isDirectory() && !dir.mkdir()) {
throw new CodegenRuntimeException("Could not create " + dir.getPath());
}
}
}
return dir;
}
/**
* 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.
*/
static String createUniqueSymbol(CNode node, String basis) {
Set usedSymbols = Arrays.stream(node.getChildren()).map(CNode::getName).collect(Collectors.toSet());
Random rng = new Random();
for (int i = 1;; i++) {
String candidate = (i < basis.length()) ? basis.substring(0, i)
: ReservedWords.INTERNAL_PREFIX + basis + rng.nextInt(Integer.MAX_VALUE);
if ( ! usedSymbols.contains(candidate)) {
return candidate;
}
}
}
public String className() {
return className;
}
public String javaPackage() {
return javaPackage;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy