From f895098c15a165376aff89059ce835cadcb44229 Mon Sep 17 00:00:00 2001 From: Peter Kajsa Date: Tue, 13 Oct 2015 17:29:24 +0200 Subject: [PATCH] Bug 4459 - Parser fails when enum contains illegal characters for QName. RFC6020 defines enum argument as string, but we need to parse QName from it due to binding part of yangtools. However, parsing of the enum containing illegal characters for QName causes IllegalArgumentException. Change-Id: Iccd5523e12ca9bdfa44efd0fab09ef764990b837 Signed-off-by: Peter Kajsa --- .../yang/parser/stmt/rfc6020/Utils.java | 25 ++++++++- .../type/EnumEffectiveStatementImpl.java | 25 +++++++-- .../yangtools/yang/stmt/test/Bug4459Test.java | 51 +++++++++++++++++++ .../src/test/resources/bugs/bug4459/foo.yang | 27 ++++++++++ 4 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug4459Test.java create mode 100644 yang/yang-parser-impl/src/test/resources/bugs/bug4459/foo.yang diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java index f0e6abf835..a19e00df1c 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java @@ -64,6 +64,10 @@ public final class Utils { private static final Logger LOG = LoggerFactory.getLogger(Utils.class); private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"'); private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\''); + private static final CharMatcher LEFT_PARENTHESIS_MATCHER = CharMatcher.is('('); + private static final CharMatcher RIGHT_PARENTHESIS_MATCHER = CharMatcher.is(')'); + private static final CharMatcher AMPERSAND_MATCHER = CharMatcher.is('&'); + private static final CharMatcher QUESTION_MARK_MATCHER = CharMatcher.is('?'); private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults(); private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults(); private static final Pattern PATH_ABS = Pattern.compile("/[^/].*"); @@ -354,7 +358,24 @@ public final class Utils { public static boolean isModuleIdentifierWithoutSpecifiedRevision(final Object o) { return (o instanceof ModuleIdentifier) - && (((ModuleIdentifier) o).getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP || - ((ModuleIdentifier) o).getRevision() == SimpleDateFormatUtil.DEFAULT_BELONGS_TO_DATE); + && (((ModuleIdentifier) o).getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP || ((ModuleIdentifier) o) + .getRevision() == SimpleDateFormatUtil.DEFAULT_BELONGS_TO_DATE); + } + + /** + * Replaces illegal characters of QName by the name of the character (e.g. + * '?' is replaced by "QuestionMark" etc.). + * + * @param string + * input String + * @return result String + */ + public static String replaceIllegalCharsForQName(String string) { + string = LEFT_PARENTHESIS_MATCHER.replaceFrom(string, "LeftParenthesis"); + string = RIGHT_PARENTHESIS_MATCHER.replaceFrom(string, "RightParenthesis"); + string = AMPERSAND_MATCHER.replaceFrom(string, "Ampersand"); + string = QUESTION_MARK_MATCHER.replaceFrom(string, "QuestionMark"); + + return string; } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumEffectiveStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumEffectiveStatementImpl.java index 66847b6c54..2522f28749 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumEffectiveStatementImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumEffectiveStatementImpl.java @@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type; import java.util.Collections; import java.util.List; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.Status; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; @@ -17,25 +18,43 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.EnumStatement; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DescriptionEffectiveStatementImpl; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ReferenceEffectiveStatementImpl; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.StatusEffectiveStatementImpl; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ValueEffectiveStatementImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class EnumEffectiveStatementImpl extends DeclaredEffectiveStatementBase implements EnumPair { + + private static final Logger LOG = LoggerFactory.getLogger(EnumEffectiveStatementImpl.class); + private final SchemaPath path; private String description; private String reference; private Status status = Status.CURRENT; private Integer value; + private final QName maybeQNameArgument; public EnumEffectiveStatementImpl(final StmtContext ctx) { super(ctx); - path = ctx.getSchemaPath().get(); + SchemaPath parentPath = ctx.getParentContext().getSchemaPath().get(); + QNameModule moduleQName = parentPath.getLastComponent().getModule(); + QName maybeQNameArgumentInit = null; + try { + maybeQNameArgumentInit = QName.create(moduleQName, argument()); + } catch (IllegalArgumentException e) { + String localName = Utils.replaceIllegalCharsForQName(argument()); + LOG.warn("{}. Enum argument '{}' has been replaced by '{}'.", e.getMessage(), argument(), localName, e); + maybeQNameArgumentInit = QName.create(moduleQName, localName); + } + this.maybeQNameArgument = maybeQNameArgumentInit; + this.path = parentPath.createChild(this.maybeQNameArgument); - for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { + for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { if (effectiveStatement instanceof DescriptionEffectiveStatementImpl) { description = ((DescriptionEffectiveStatementImpl) effectiveStatement).argument(); } @@ -63,7 +82,7 @@ public class EnumEffectiveStatementImpl extends DeclaredEffectiveStatementBase type = myLeaf.getType(); + assertTrue(type instanceof EnumTypeDefinition); + EnumTypeDefinition myEnum = (EnumTypeDefinition) type; + + QName expectedEnumQName = QName.create("foo", "1970-01-01", "QuestionMark-Ampersand-LeftParenthesis-RightParenthesis-QuestionMark-QuestionMark-Ampersand"); + List values = myEnum.getValues(); + for (EnumPair enumPair : values) { + if (enumPair.getName().equals("?-&-(-)-?-?-&")) { + assertEquals(expectedEnumQName, enumPair.getQName()); + } + } + } +} diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug4459/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug4459/foo.yang new file mode 100644 index 0000000000..31ee8eafd0 --- /dev/null +++ b/yang/yang-parser-impl/src/test/resources/bugs/bug4459/foo.yang @@ -0,0 +1,27 @@ +module foo { + namespace foo; + prefix foo; + yang-version 1; + + extension e { + argument a { + foo:e2 a { + type enumeration { + enum "?"; + enum "*"; + } + } + } + } + + extension e2 { + argument name; + } + + leaf my-leaf { + type enumeration { + enum "?-&-(-)-?-?-&"; + enum "*"; + } + } +} -- 2.36.6