You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hudi.apache.org by yi...@apache.org on 2023/02/23 00:31:14 UTC
[hudi] branch asf-site updated: [DOCS] Change Config generator to generate subgroups (#7970)
This is an automated email from the ASF dual-hosted git repository.
yihua pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/hudi.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 48bc60d8298 [DOCS] Change Config generator to generate subgroups (#7970)
48bc60d8298 is described below
commit 48bc60d82988d02c14c4d75e263a1f9823edfd17
Author: Bhavani Sudha Saktheeswaran <21...@users.noreply.github.com>
AuthorDate: Wed Feb 22 16:31:05 2023 -0800
[DOCS] Change Config generator to generate subgroups (#7970)
Changes Config generator to generate subgroups. Also, makes changes so that required configs bubble up to the top of the section.
---
hudi-utils/generate_config.sh | 2 +-
hudi-utils/pom.xml | 8 +-
.../hudi/utils/HoodieConfigDocGenerator.java | 325 ++++++++++++++++-----
3 files changed, 263 insertions(+), 72 deletions(-)
diff --git a/hudi-utils/generate_config.sh b/hudi-utils/generate_config.sh
index 89900de8b00..64e2b3dceef 100755
--- a/hudi-utils/generate_config.sh
+++ b/hudi-utils/generate_config.sh
@@ -17,7 +17,7 @@
# limitations under the License.
#
-VERSION=0.13.0
+VERSION=0.14.0
JARS=(
"$HOME/.m2/repository/org/apache/hudi/hudi-utilities-bundle_2.11/$VERSION-SNAPSHOT/hudi-utilities-bundle_2.11-$VERSION-SNAPSHOT.jar"
diff --git a/hudi-utils/pom.xml b/hudi-utils/pom.xml
index 2272f6b9609..90863a88a39 100644
--- a/hudi-utils/pom.xml
+++ b/hudi-utils/pom.xml
@@ -27,7 +27,7 @@
<properties>
<jdk.version>1.8</jdk.version>
- <hudi.version>0.13.0-SNAPSHOT</hudi.version>
+ <hudi.version>0.14.0-SNAPSHOT</hudi.version>
<hudi.spark.module>hudi-spark2</hudi.spark.module>
<scala.binary.version>2.11</scala.binary.version>
<junit.version>4.11</junit.version>
@@ -74,6 +74,12 @@
<version>${hudi.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.hive</groupId>
+ <artifactId>hive-common</artifactId>
+ <version>2.3.1</version>
+ </dependency>
+
<!-- Logging -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
diff --git a/hudi-utils/src/main/java/org/apache/hudi/utils/HoodieConfigDocGenerator.java b/hudi-utils/src/main/java/org/apache/hudi/utils/HoodieConfigDocGenerator.java
index 1533599e936..4073f00bd8d 100644
--- a/hudi-utils/src/main/java/org/apache/hudi/utils/HoodieConfigDocGenerator.java
+++ b/hudi-utils/src/main/java/org/apache/hudi/utils/HoodieConfigDocGenerator.java
@@ -47,11 +47,15 @@ import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.EnumSet;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import static org.apache.hudi.common.config.ConfigGroups.SubGroupNames.NONE;
import static org.reflections.ReflectionUtils.getAllFields;
import static org.reflections.ReflectionUtils.withTypeAssignableTo;
@@ -76,10 +80,14 @@ public class HoodieConfigDocGenerator {
"file `hudi-default.conf`. By default, Hudi would load the configuration file under `/etc/hudi/conf` directory. You can\n" +
"specify a different configuration directory location by setting the `HUDI_CONF_DIR` environment variable. This can be\n" +
"useful for uniformly enforcing repeated configs (like Hive sync or write/index tuning), across your entire data lake.";
+ private static final Integer DEFAULT_CONFIG_GROUP_HEADING_LEVEL = 2;
+ private static final Integer DEFAULT_CONFIG_PARAM_HEADING_LEVEL = 3;
public static void main(String[] args) {
Reflections reflections = new Reflections("org.apache.hudi");
- Set<Class<? extends HoodieConfig>> subTypes = reflections.getSubTypesOf(HoodieConfig.class);
+ // Scan and collect meta info of all HoodieConfig superclasses by using reflection
+ List<HoodieConfigClassMetaInfo> hoodieConfigClassMetaInfos = getSortedListOfHoodieConfigClassMetaInfo(reflections.getSubTypesOf(HoodieConfig.class));
+
// Top heading
StringBuilder mainDocBuilder = new StringBuilder();
generateHeader(mainDocBuilder);
@@ -91,44 +99,61 @@ public class HoodieConfigDocGenerator {
// and also does not use ConfigClassProperty
populateSparkConfigs(contentMap);
- // Automated: Scan through all HoodieConfig superclasses using reflection
- for (Class<? extends HoodieConfig> subType : subTypes) {
- // sub-heading using the annotation
- ConfigClassProperty configGroupProperty = subType.getAnnotation(ConfigClassProperty.class);
- try {
- if (configGroupProperty != null) {
- StringBuilder configParamsBuilder = contentMap.get(configGroupProperty.groupName());
- LOG.info("Processing params for config class: " + subType.getName() + " " + configGroupProperty.name()
- + " " + configGroupProperty.description());
- configParamsBuilder.append("### ").append(configGroupProperty.name())
- .append(" {" + "#").append(configGroupProperty.name().replace(" ", "-")).append("}")
- .append(DOUBLE_NEWLINE);
- configParamsBuilder.append(configGroupProperty.description()).append(DOUBLE_NEWLINE);
-
- configParamsBuilder
+ // generate Docs from the config classes
+ ConfigGroups.SubGroupNames prevSubGroupName = NONE;
+ boolean isPartOfSubGroup = false;
+ int configParamHeadingLevel = DEFAULT_CONFIG_PARAM_HEADING_LEVEL;
+ for (HoodieConfigClassMetaInfo configClassMetaInfo: hoodieConfigClassMetaInfos) {
+ Class<? extends HoodieConfig> subType = configClassMetaInfo.subType;
+ ConfigClassProperty configClassProperty = subType.getAnnotation(ConfigClassProperty.class);
+ StringBuilder groupOrSubGroupStringBuilder = contentMap.get(configClassProperty.groupName());
+ LOG.info("Processing params for config class: " + subType.getName() + " " + configClassProperty.name()
+ + " " + configClassProperty.description());
+ if (configClassMetaInfo.subGroupName == NONE){
+ isPartOfSubGroup = false;
+ configParamHeadingLevel = DEFAULT_CONFIG_PARAM_HEADING_LEVEL;
+ } else if (configClassMetaInfo.subGroupName == prevSubGroupName) {
+ // Continuation of more HoodieConfig classes that are part of the same subgroup
+ isPartOfSubGroup = true;
+ groupOrSubGroupStringBuilder = new StringBuilder();
+ configParamHeadingLevel = DEFAULT_CONFIG_PARAM_HEADING_LEVEL + 1;
+ } else if (configClassMetaInfo.hasCommonConfigs) {
+ // This is a new valid Subgroup encountered. Add description for the subgroup.
+ isPartOfSubGroup = true;
+ groupOrSubGroupStringBuilder = new StringBuilder();
+ generateConfigGroupSummary(groupOrSubGroupStringBuilder,
+ configClassMetaInfo.subGroupName.name,
+ configClassMetaInfo.subGroupName.name(),
+ configClassProperty.subGroupName().getDescription(),
+ DEFAULT_CONFIG_GROUP_HEADING_LEVEL + 1);
+ configParamHeadingLevel = DEFAULT_CONFIG_PARAM_HEADING_LEVEL + 1;
+ }
+ prevSubGroupName = configClassMetaInfo.subGroupName;
+ generateConfigGroupSummary(groupOrSubGroupStringBuilder,
+ configClassProperty.name(),
+ configClassProperty.name().replace(" ", "-"),
+ configClassProperty.description(),
+ configParamHeadingLevel);
+ groupOrSubGroupStringBuilder
.append("`")
.append(new Text("Config Class"))
.append("`")
.append(": ")
.append(subType.getName()).append(LINE_BREAK);
- // Special casing Flink Configs since the class does not use ConfigClassProperty
- // Also, we need to split Flink Options into Flink Read Options, Write Options...
- if (subType.getName().equals(FLINK_CONFIG_CLASS_NAME)) {
- generateFlinkConfigMarkup(subType, configParamsBuilder);
- } else {
- Set<Field> fields = getAllFields(subType, withTypeAssignableTo(ConfigProperty.class));
- for (Field field : fields) {
- generateConfigMarkup(subType, field, null, configParamsBuilder);
- }
- }
- } else {
- LOG.error("FATAL error Please add `ConfigClassProperty` annotation for " + subType.getName());
+ // Special casing Flink Configs since the class does not use ConfigClassProperty
+ // Also, we need to split Flink Options into Flink Read Options, Write Options...
+ if (subType.getName().equals(FLINK_CONFIG_CLASS_NAME)) {
+ generateFlinkConfigMarkup(subType, groupOrSubGroupStringBuilder);
+ } else {
+ generateAllOtherConfigs(subType, isPartOfSubGroup, groupOrSubGroupStringBuilder);
+ if (isPartOfSubGroup) {
+ // If the config class is part of a subgroup, close the string builder for subgroup and append it to the main group builder.
+ contentMap.get(configClassProperty.groupName()).append(groupOrSubGroupStringBuilder.toString());
}
- } catch (Exception e) {
- LOG.error("FATAL error while processing config class: " + subType.getName(), e);
}
}
+
try {
LOG.info("Generating markdown file");
mainDocBuilder.append(contentTableBuilder.build()).append(DOUBLE_NEWLINE);
@@ -140,6 +165,32 @@ public class HoodieConfigDocGenerator {
}
}
+ private static List<HoodieConfigClassMetaInfo> getSortedListOfHoodieConfigClassMetaInfo(Set<Class<? extends HoodieConfig>> subTypes) {
+ // Scan and collect meta info of all HoodieConfig superclasses by using reflection
+ List<HoodieConfigClassMetaInfo> hoodieConfigClassMetaInfos = new ArrayList<>();
+ for (Class<? extends HoodieConfig> subType : subTypes) {
+ // sub-heading using the annotation
+ ConfigClassProperty configClassProperty = subType.getAnnotation(ConfigClassProperty.class);
+ try{
+ if (configClassProperty != null) {
+ hoodieConfigClassMetaInfos.add(new HoodieConfigClassMetaInfo(configClassProperty.groupName(), configClassProperty.subGroupName(), configClassProperty.areCommonConfigs(), subType));
+ } else {
+ LOG.error("FATAL error Please add `ConfigClassProperty` annotation for " + subType.getName());
+ }
+ } catch (Exception e) {
+ LOG.error("FATAL error while processing config class: " + subType.getName(), e);
+ }
+ }
+
+ // Now sort them based on these columns in the order - groupname, subgroupname (reverse order) and areCommonConfigs (reverse order)
+ // We want to list all groups with no subgroups first. Followed by groups with subgroups and among them list the
+ // class that has common configs first.
+ hoodieConfigClassMetaInfos.sort(Comparator.comparing(HoodieConfigClassMetaInfo::getGroupName)
+ .thenComparing(HoodieConfigClassMetaInfo::getSubGroupName, Comparator.reverseOrder())
+ .thenComparing(HoodieConfigClassMetaInfo::areCommonConfigs, Comparator.reverseOrder()));
+ return hoodieConfigClassMetaInfos;
+ }
+
private static void generateHeader(StringBuilder builder) {
/*
---
@@ -148,6 +199,8 @@ public class HoodieConfigDocGenerator {
permalink: /docs/configurations.html
summary: This section offers an overview of tools available to operate an ecosystem of Hudi
toc: true
+ toc_min_heading_level: 2
+ toc_max_heading_level: 4
last_modified_at: 2019-12-30T15:59:57-04:00
---
*/
@@ -158,6 +211,8 @@ public class HoodieConfigDocGenerator {
.append("permalink: /docs/configurations.html").append(NEWLINE)
.append("summary: " + SUMMARY).append(NEWLINE)
.append("toc: true").append(NEWLINE)
+ .append("toc_min_heading_level: 2").append(NEWLINE)
+ .append("toc_max_heading_level: 4").append(NEWLINE)
.append("last_modified_at: " + DateTimeFormatter.ISO_DATE_TIME.format(now)).append(NEWLINE)
.append(new HorizontalRule())
.append(DOUBLE_NEWLINE);
@@ -173,17 +228,29 @@ public class HoodieConfigDocGenerator {
Map<ConfigGroups.Names, StringBuilder> contentMap = new LinkedHashMap<>();
EnumSet.allOf(ConfigGroups.Names.class).forEach(groupName -> {
StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append("## ")
- .append(groupName.name)
- .append(" {" + "#").append(groupName.name()).append("}")
- .append(NEWLINE)
- .append(ConfigGroups.getDescription(groupName))
- .append(DOUBLE_NEWLINE);
+ generateConfigGroupSummary(stringBuilder, groupName.name, groupName.name(), ConfigGroups.getDescription(groupName), DEFAULT_CONFIG_GROUP_HEADING_LEVEL);
contentMap.put(groupName, stringBuilder);
});
return contentMap;
}
+ private static void generateConfigGroupSummary(StringBuilder stringBuilder, String friendlyName, String groupName, String description, int headingSize) {
+ stringBuilder.append(getHeadingSizeMarkup(headingSize))
+ .append(friendlyName)
+ .append(" {" + "#").append(groupName).append("}")
+ .append(NEWLINE)
+ .append(description)
+ .append(DOUBLE_NEWLINE);
+ }
+
+ private static String getHeadingSizeMarkup(int headingSize){
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < headingSize; i++) {
+ stringBuilder.append("#");
+ }
+ stringBuilder.append(" ");
+ return stringBuilder.toString();
+ }
private static StringBuilder generateExternalizedConfigs() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(EXTERNALIZED_CONFIGS);
@@ -212,17 +279,26 @@ public class HoodieConfigDocGenerator {
Set<Field> hardcodedFields = ReflectionUtils.getAllFields(sparkConfigObject.getClass(), withTypeAssignableTo(ConfigProperty.class));
+
+ List<ConfigMarkup> allConfigs = new ArrayList<>();
for (Field field : hardcodedFields) {
field.setAccessible(true);
- generateConfigMarkup(sparkConfigObject.getClass(), field, sparkConfigObject, configParamsBuilder);
+ ConfigMarkup configMarkup = generateConfigMarkup(sparkConfigObject.getClass(), field, sparkConfigObject, DEFAULT_CONFIG_PARAM_HEADING_LEVEL);
+ allConfigs.add(configMarkup);
}
+ // sort the configs based on config key prefix and add to the configParamsBuilder
+ allConfigs.sort(Comparator.comparing(ConfigMarkup::isConfigRequired).reversed()
+ .thenComparing(ConfigMarkup::getConfigKey));
+ allConfigs.forEach(cfg -> configParamsBuilder.append(cfg.configMarkupString));
}
}
private static void generateFlinkConfigMarkup(Class subType, StringBuilder configParamsBuilder) {
try {
+ List<ConfigMarkup> allConfigs = new ArrayList();
Set<Field> fields = getAllFields(FlinkOptions.class, withTypeAssignableTo(ConfigOption.class));
for (Field field : fields) {
+ StringBuilder tmpConfigParamBuilder = new StringBuilder();
ConfigOption cfgProperty = (ConfigOption) field.get(null);
String description = new HtmlFormatter().format(cfgProperty.description());
if (description.isEmpty()) {
@@ -232,99 +308,208 @@ public class HoodieConfigDocGenerator {
+ field.getName());
}
// Config Header
- configParamsBuilder.append("> ").append("#### ").append(new Text(cfgProperty.key())).append(NEWLINE);
+ tmpConfigParamBuilder.append("> ").append("#### ").append(new Text(cfgProperty.key())).append(NEWLINE);
// Description
- configParamsBuilder
+ tmpConfigParamBuilder
.append("> ")
.append(description)
.append(LINE_BREAK);
// Default value
- addDefaultValue(configParamsBuilder, cfgProperty.hasDefaultValue() ? cfgProperty.defaultValue() : null);
+ Object defaultValue = cfgProperty.hasDefaultValue() ? cfgProperty.defaultValue() : null;
+ addDefaultValue(tmpConfigParamBuilder, defaultValue);
+ boolean isConfigRequired = (defaultValue == null);
+
+ // TODO: Custom config tags like "Doc on Default Value:" cannot be added for Flink.
+ // ConfigOption is a Flink class. In order to support custom config apis like getDocOnDefaultValue
+ // this class needs to be wrapped in Hudi first.
// Config param name
- generateConfigKeyValue(configParamsBuilder, true, "Config Param", field.getName());
+ generateConfigKeyValue(tmpConfigParamBuilder, "Config Param", field.getName());
- configParamsBuilder
+ tmpConfigParamBuilder
.append(NEWLINE)
.append(new HorizontalRule(3))
.append(DOUBLE_NEWLINE);
+
+ ConfigMarkup configMarkup = new ConfigMarkup(cfgProperty.key(), isConfigRequired, tmpConfigParamBuilder.toString());
+ allConfigs.add(configMarkup);
}
+
+ // sort the configs based on config key prefix and add to the configParamsBuilder
+ allConfigs.sort(Comparator.comparing(ConfigMarkup::isConfigRequired).reversed()
+ .thenComparing(ConfigMarkup::getConfigKey));
+ allConfigs.forEach(cfg -> configParamsBuilder.append(cfg.configMarkupString));
} catch (IllegalAccessException e) {
LOG.error("Error while getting field through reflection for config class: " + subType.getName(), e);
}
}
- private static void generateConfigMarkup(Class subType, Field field, Object object, StringBuilder configParamsBuilder) {
+ private static void generateAllOtherConfigs(Class<? extends HoodieConfig> subType, boolean isPartOfSubGroup, StringBuilder stringBuilder) {
+ Set<Field> fields = getAllFields(subType, withTypeAssignableTo(ConfigProperty.class));
+ List<ConfigMarkup> allConfigs = new ArrayList<>();
+ for (Field field : fields) {
+ ConfigMarkup configMarkup = generateConfigMarkup(subType, field, null, isPartOfSubGroup? DEFAULT_CONFIG_PARAM_HEADING_LEVEL + 1 : DEFAULT_CONFIG_PARAM_HEADING_LEVEL);
+ allConfigs.add(configMarkup);
+ }
+ // sort the configs based on config key prefix and add to the configParamsBuilder
+ allConfigs.sort(Comparator.comparing(ConfigMarkup::isConfigRequired).reversed()
+ .thenComparing(ConfigMarkup::getConfigKey));
+ for (ConfigMarkup cfg: allConfigs) {
+ stringBuilder.append(cfg.configMarkupString);
+ }
+ }
+
+ private static ConfigMarkup generateConfigMarkup(Class subType, Field field, Object object, int headingLevel) {
try {
+ StringBuilder configParamsBuilder = new StringBuilder();
ConfigProperty cfgProperty = (ConfigProperty) field.get(object);
if (StringUtils.isNullOrEmpty(cfgProperty.doc())) {
LOG.warn("Found empty or null description for config class = "
- + subType.getName()
- + " for param = "
- + field.getName());
+ + subType.getName()
+ + " for param = "
+ + field.getName());
}
// Config Header
- configParamsBuilder.append("> ").append("#### ").append(new Text(cfgProperty.key())).append(NEWLINE);
+ configParamsBuilder.append("> ").append(getHeadingSizeMarkup(headingLevel)).append(new Text(cfgProperty.key())).append(NEWLINE);
// Description
String description = StringUtils.isNullOrEmpty(cfgProperty.doc()) ? "" : cfgProperty.doc();
configParamsBuilder
- .append("> ")
- .append(description)
- .append(LINE_BREAK);
+ .append("> ")
+ .append(description)
+ .append(LINE_BREAK);
// Default value
- addDefaultValue(configParamsBuilder, cfgProperty.hasDefaultValue() ? cfgProperty.defaultValue() : null);
+ Object defaultValue = cfgProperty.hasDefaultValue() ? cfgProperty.defaultValue() : (cfgProperty.hasInferFunction() ? "" : null );
+ addDefaultValue(configParamsBuilder, defaultValue);
+ boolean isConfigRequired = (defaultValue == null);
+
+ // Note on Default value
+ if (StringUtils.nonEmpty(cfgProperty.getDocOnDefaultValue()) && !cfgProperty.getDocOnDefaultValue().equals(StringUtils.EMPTY_STRING)) {
+ addDocOnDefaultValue(configParamsBuilder, cfgProperty.getDocOnDefaultValue());
+ }
// Config param name
- generateConfigKeyValue(configParamsBuilder, true, "Config Param", field.getName());
+ generateConfigKeyValue(configParamsBuilder, "Config Param", field.getName());
// First version
if (cfgProperty.getSinceVersion().isPresent()) {
- generateConfigKeyValue(configParamsBuilder, true, "Since Version", cfgProperty.getSinceVersion().get());
+ generateConfigKeyValue(configParamsBuilder, "Since Version", String.valueOf(cfgProperty.getSinceVersion().get()));
}
if (cfgProperty.getDeprecatedVersion().isPresent()) {
- generateConfigKeyValue(configParamsBuilder, true, "Deprecated Version", cfgProperty.getDeprecatedVersion().get());
+ generateConfigKeyValue(configParamsBuilder, "Deprecated Version", String.valueOf(cfgProperty.getDeprecatedVersion().get()));
}
configParamsBuilder
- .append(NEWLINE)
- .append(new HorizontalRule(3))
- .append(DOUBLE_NEWLINE);
+ .append(NEWLINE)
+ .append(new HorizontalRule(3))
+ .append(DOUBLE_NEWLINE);
+ return new ConfigMarkup(cfgProperty.key(), isConfigRequired, configParamsBuilder.toString());
} catch (IllegalAccessException e) {
LOG.error("Error while getting field through reflection for config class: " + subType.getName(), e);
+ throw new IllegalArgumentException("Error while getting field through reflection for config class: " + subType.getName(), e);
}
}
private static void addDefaultValue(StringBuilder builder, @Nullable Object defaultValue) {
- generateConfigKeyValue(builder, false, "Default Value",
- (defaultValue != null) ? defaultValue + " (Optional)" : "N/A (Required)");
+ boolean isRequired = false;
+ if (defaultValue != null) {
+ builder
+ .append("> ")
+ .append("`")
+ .append(new Text("Default Value"))
+ .append(": ")
+ .append(new Text(defaultValue + " (Optional)"))
+ .append("`")
+ .append(LINE_BREAK);
+ } else {
+ builder
+ .append("> ")
+ .append("`")
+ .append(new Text("Default Value"))
+ .append(": N/A ")
+ .append("`")
+ .append(new BoldText("(Required)"))
+ .append(LINE_BREAK);
+ // TODO: Use this to highlight required configs blue in a later release. We are not enabling this now since we need
+ // to review required configs in Hudi repo first towards simplification.
+ //.append(new BoldText("<span style={{color: '#0db1f9'}}>(Required)</span>"))
+ }
+ }
+
+ private static void addDocOnDefaultValue(StringBuilder builder, String value) {
+ generateConfigKeyValue(builder, "Note on Default Value", value);
}
private static void generateConfigKeyValue(StringBuilder builder,
- boolean shouldHighlight,
String key,
- Object value) {
- if (shouldHighlight) {
+ String value) {
builder
.append("> ")
.append("`")
.append(new Text(key))
.append(": ")
- .append(new Text(value))
+ .append(value)
.append("`")
.append(LINE_BREAK);
- } else {
- builder
- .append("> ")
- .append(new BoldText(key))
- .append(": ")
- .append(new Text(value))
- .append(LINE_BREAK);
+ }
+
+ /**
+ Class for storing info about each config within a HoodieConfig class subtype. We want to know if a config is required or not. And also store the config key
+ along with the markup. We can use this info to pull up all required configs and also sort configs based on prefix
+ for better readability.
+ **/
+
+ static class ConfigMarkup {
+ String configKey;
+ boolean isConfigRequired;
+ String configMarkupString;
+
+ ConfigMarkup(String configKey, boolean isConfigRequired, String configMarkupString){
+ this.configKey = configKey;
+ this.isConfigRequired = isConfigRequired;
+ this.configMarkupString = configMarkupString;
+ }
+
+ public boolean isConfigRequired() {
+ return isConfigRequired;
+ }
+
+ public String getConfigKey() {
+ return configKey;
+ }
+ }
+
+ /**
+ * Class for storing meta info about each HoodiConfig class subtype. This class has info on the group name, subgroup
+ * name if any, indication of whether this subtype has common configs for that subgroup and the subtype itself.
+ */
+ static class HoodieConfigClassMetaInfo {
+ ConfigGroups.Names groupName;
+ ConfigGroups.SubGroupNames subGroupName;
+ boolean hasCommonConfigs;
+ Class<? extends HoodieConfig> subType;
+ HoodieConfigClassMetaInfo(ConfigGroups.Names groupName, ConfigGroups.SubGroupNames subGroupName, boolean hasCommonConfigs, Class<? extends HoodieConfig> subType) {
+ this.groupName = groupName;
+ this.subGroupName = subGroupName;
+ this.hasCommonConfigs = hasCommonConfigs;
+ this.subType = subType;
+ }
+
+ public ConfigGroups.Names getGroupName() {
+ return groupName;
+ }
+
+ public ConfigGroups.SubGroupNames getSubGroupName() {
+ return subGroupName;
+ }
+
+ public boolean areCommonConfigs() {
+ return hasCommonConfigs;
}
}
}