Bug 4459 - Parser fails when enum contains illegal characters for QName. 71/32871/1
authorPeter Kajsa <pkajsa@cisco.com>
Tue, 13 Oct 2015 15:29:24 +0000 (17:29 +0200)
committerRobert Varga <nite@hq.sk>
Sat, 16 Jan 2016 14:38:17 +0000 (14:38 +0000)
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 <pkajsa@cisco.com>
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/EnumEffectiveStatementImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug4459Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bugs/bug4459/foo.yang [new file with mode: 0644]

index f0e6abf83509fc69c87570c2883522714b7a8bb6..a19e00df1cdee1b2fb1249e1dabd196c484929bd 100644 (file)
@@ -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;
     }
 }
index 66847b6c542f7a7dfc78ec90af200ad0e5bd9149..2522f2874944ba53376d57b344283bdbc1a705c2 100644 (file)
@@ -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<String, EnumStatement> 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<String, EnumStatement, ?> 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<S
 
     @Override
     public QName getQName() {
-        return getPath().getLastComponent();
+        return maybeQNameArgument;
     }
 
     @Override
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug4459Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug4459Test.java
new file mode 100644 (file)
index 0000000..2d95e5f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.stmt.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+public class Bug4459Test {
+
+    @Test
+    public void test() throws IOException, URISyntaxException, SourceException, ReactorException {
+        SchemaContext schema = StmtTestUtils.parseYangSources("/bugs/bug4459");
+        assertNotNull(schema);
+
+        DataSchemaNode dataChildByName = schema.getDataChildByName("my-leaf");
+        assertTrue(dataChildByName instanceof LeafSchemaNode);
+        LeafSchemaNode myLeaf = (LeafSchemaNode) dataChildByName;
+
+        TypeDefinition<?> 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<EnumPair> 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 (file)
index 0000000..31ee8ea
--- /dev/null
@@ -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 "*";
+        }
+    }
+}