import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
/**
* A configuration of {@link YangParser} wiring for use with {@link YangParserFactory}.
private final ImportResolutionMode importResolutionMode;
private final boolean retainDeclarationReferences;
+ private final boolean warnForUnkeyedLists;
private YangParserConfiguration(final ImportResolutionMode importResolutionMode,
- final boolean retainDeclarationReferences) {
+ final boolean retainDeclarationReferences, final boolean warnForUnkeyedLists) {
this.importResolutionMode = requireNonNull(importResolutionMode);
this.retainDeclarationReferences = retainDeclarationReferences;
+ this.warnForUnkeyedLists = warnForUnkeyedLists;
}
@Beta
return importResolutionMode;
}
+ /**
+ * Return {@code true} if {@link DeclarationReference} to source location in the final parser product, notably
+ * making {@link DeclaredStatement#declarationReference()} available.
+ *
+ * @return {@code true} if declaration references should be retained
+ */
public boolean retainDeclarationReferences() {
return retainDeclarationReferences;
}
+ /**
+ * Issue a warning when a {@code list} statement without a {@code key} statement is found in the
+ * {@code config true} part of the schema tree. Such statements run contrary to
+ * <a href="https://www.rfc-editor.org/rfc/rfc7950.html#section-7.8.2">RFC7950</a>, but are readily supported
+ * by OpenDaylight infrastructure.
+ *
+ * @return {@code true} if non-compliant {@code list} statements should be reported
+ */
+ public boolean warnForUnkeyedLists() {
+ return warnForUnkeyedLists;
+ }
+
@Override
public int hashCode() {
return Objects.hash(importResolutionMode, retainDeclarationReferences);
.toString();
}
+ /**
+ * Return a new {@link Builder} initialized to default configuration.
+ *
+ * @return A new builder
+ */
public static Builder builder() {
return new Builder();
}
public static final class Builder implements Mutable {
private ImportResolutionMode importResolutionMode = ImportResolutionMode.DEFAULT;
- private boolean retainDeclarationReferences = false;
+ private boolean retainDeclarationReferences;
+ // FIXME: YANGTOOLS-1423: default to false
+ private boolean warnForUnkeyedLists = true;
private Builder() {
// Hidden on purpose
* @return A YangParserConfiguration
*/
public YangParserConfiguration build() {
- return new YangParserConfiguration(importResolutionMode, retainDeclarationReferences);
+ return new YangParserConfiguration(importResolutionMode, retainDeclarationReferences, warnForUnkeyedLists);
}
@Beta
return this;
}
+ /**
+ * Retain {@link DeclarationReference} to source location in the final parser product. This option results in
+ * quite significant memory overhead for storage of {@link DeclaredStatement}, but makes
+ * {@link DeclaredStatement#declarationReference()} available, which is useful in certain scenarios, for example
+ * YANG editors.
+ *
+ * <p>
+ * This option is disabled by default.
+ *
+ * @param newRetainDeclarationReferences {@code true} if declaration references should be retained
+ * @return This builder
+ */
public Builder retainDeclarationReferences(final boolean newRetainDeclarationReferences) {
retainDeclarationReferences = newRetainDeclarationReferences;
return this;
}
+
+ /**
+ * Issue a warning when a {@code list} statement without a {@code key} statement is found in the
+ * {@code config true} part of the schema tree. Such statements run contrary to
+ * <a href="https://www.rfc-editor.org/rfc/rfc7950.html#section-7.8.2">RFC7950</a>, but are readily supported
+ * by OpenDaylight infrastructure.
+ *
+ * <p>
+ * This option is enabled by default.
+ *
+ * @param newWarnForUnkeyedLists {@code true} if non-compliant {@code list} statements should be reported
+ * @return This builder
+ */
+ public Builder warnForUnkeyedLists(final boolean newWarnForUnkeyedLists) {
+ warnForUnkeyedLists = newWarnForUnkeyedLists;
+ return this;
+ }
}
}
.addOptional(YangStmtMapping.WHEN)
.build();
+ private final boolean warnForUnkeyedLists;
+
ListStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
super(YangStmtMapping.LIST, instantiatedPolicy(), config, validator);
+ this.warnForUnkeyedLists = config.warnForUnkeyedLists();
}
public static @NonNull ListStatementSupport rfc6020Instance(final YangParserConfiguration config) {
}
final int flags = computeFlags(stmt, substatements);
- if (stmt.effectiveConfig() == EffectiveConfig.TRUE && keyDefinition.isEmpty() && isInstantied(stmt)) {
+ if (warnForUnkeyedLists && stmt.effectiveConfig() == EffectiveConfig.TRUE
+ && keyDefinition.isEmpty() && isInstantied(stmt)) {
warnConfigList(stmt);
}
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
- <version>1.4</version>
+ <version>1.5.0</version>
</dependency>
</dependencies>
* -v, --verbose shows details about the results of test running.
* -o, --output path to output file for logs. Output file will be overwritten.
* -m, --module-name validate yang by module name.
+ * -wul, --warning-for-unkeyed-lists
+ * add warnings about unkeyed lists with config true.
*/
@SuppressWarnings({"checkstyle:LoggerMustBeSlf4j", "checkstyle:LoggerFactoryClassParameter"})
public final class Main {
private static final Option QUIET = new Option("q", "quiet", false, "completely suppress output.");
private static final Option VERBOSE = new Option("v", "verbose", false,
"shows details about the results of test running.");
+ private static final Option LIST_WARNING_ON = new Option("wul", "warning-for-unkeyed-lists", false,
+ "add warnings about unkeyed lists with config true");
+ private static final Option LIST_WARNING_OFF = new Option("no-wul", "no-warning-for-unkeyed-lists", false,
+ "do not add warnings about unkeyed lists with config true");
private Main() {
// Hidden on purpose
}
private static Options createOptions() {
- final Options options = new Options();
- options.addOption(HELP);
- options.addOption(PATH);
- options.addOption(RECURSIVE);
-
- final OptionGroup verbosity = new OptionGroup();
- verbosity.addOption(DEBUG);
- verbosity.addOption(QUIET);
- verbosity.addOption(VERBOSE);
- options.addOptionGroup(verbosity);
-
- options.addOption(OUTPUT);
- options.addOption(MODULE_NAME);
- options.addOption(FEATURE);
- return options;
+ return new Options()
+ .addOption(HELP)
+ .addOption(PATH)
+ .addOption(RECURSIVE)
+ .addOptionGroup(new OptionGroup().addOption(DEBUG).addOption(QUIET).addOption(VERBOSE))
+ .addOptionGroup(new OptionGroup().addOption(LIST_WARNING_ON).addOption(LIST_WARNING_OFF))
+ .addOption(OUTPUT)
+ .addOption(MODULE_NAME)
+ .addOption(FEATURE);
}
public static void main(final String[] args) {
LOG_ROOT.detachAndStopAllAppenders();
}
+ final boolean warnForUnkeyedLists;
+ if (arguments.hasOption(LIST_WARNING_ON.getLongOpt()) || !arguments.hasOption(LIST_WARNING_OFF.getLongOpt())) {
+ warnForUnkeyedLists = true;
+ } else {
+ warnForUnkeyedLists = false;
+ }
+
final List<String> yangLibDirs = initYangDirsPath(arguments);
final List<String> yangFiles = new ArrayList<>();
final String[] moduleNameValues = arguments.getOptionValues(MODULE_NAME.getLongOpt());
final Set<QName> supportedFeatures = initSupportedFeatures(arguments);
- runSystemTest(yangLibDirs, yangFiles, supportedFeatures, arguments.hasOption("recursive"));
+ runSystemTest(yangLibDirs, yangFiles, supportedFeatures, arguments.hasOption(RECURSIVE.getLongOpt()),
+ warnForUnkeyedLists);
LOG_ROOT.getLoggerContext().reset();
}
@SuppressFBWarnings({ "DM_EXIT", "DM_GC" })
@SuppressWarnings("checkstyle:illegalCatch")
private static void runSystemTest(final List<String> yangLibDirs, final List<String> yangFiles,
- final Set<QName> supportedFeatures, final boolean recursiveSearch) {
+ final Set<QName> supportedFeatures, final boolean recursiveSearch, final boolean warnForUnkeyedLists) {
LOG.info("Yang model dirs: {} ", yangLibDirs);
LOG.info("Yang model files: {} ", yangFiles);
LOG.info("Supported features: {} ", supportedFeatures);
final Stopwatch stopWatch = Stopwatch.createStarted();
try {
- context = SystemTestUtils.parseYangSources(yangLibDirs, yangFiles, supportedFeatures, recursiveSearch);
+ context = SystemTestUtils.parseYangSources(yangLibDirs, yangFiles, supportedFeatures,
+ recursiveSearch, warnForUnkeyedLists);
} catch (final Exception e) {
LOG.error("Failed to create SchemaContext.", e);
System.exit(1);
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.parser.api.YangParser;
+import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
import org.opendaylight.yangtools.yang.parser.api.YangParserException;
import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
};
static EffectiveModelContext parseYangSources(final List<String> yangLibDirs, final List<String> yangTestFiles,
- final Set<QName> supportedFeatures, final boolean recursiveSearch) throws IOException, YangParserException {
+ final Set<QName> supportedFeatures, final boolean recursiveSearch,
+ final boolean warnForUnkeyedLists) throws IOException, YangParserException {
/*
* Current dir "." should be always present implicitly in the list of
* directories where dependencies are searched for
}
}
- return parseYangSources(supportedFeatures, testFiles, libFiles);
+ return parseYangSources(supportedFeatures, testFiles, libFiles, warnForUnkeyedLists);
}
static EffectiveModelContext parseYangSources(final Set<QName> supportedFeatures, final List<File> testFiles,
- final List<File> libFiles) throws IOException, YangParserException {
+ final List<File> libFiles, final boolean warnForUnkeyedLists) throws IOException, YangParserException {
checkArgument(!testFiles.isEmpty(), "No yang sources");
- final YangParser parser = PARSER_FACTORY.createParser();
+ final YangParserConfiguration configuration = YangParserConfiguration.builder()
+ .warnForUnkeyedLists(warnForUnkeyedLists).build();
+ final YangParser parser = PARSER_FACTORY.createParser(configuration);
if (supportedFeatures != null) {
parser.setSupportedFeatures(supportedFeatures);
}