Validate parsed QName to identity 75/69075/3
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 22 Feb 2018 14:01:52 +0000 (15:01 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 5 Mar 2018 14:41:33 +0000 (15:41 +0100)
We need to validate if parsed QName refers to an existing identity
before allowing it in Identityref codecs. Introduce IdentityCodecUtil
along with a test suite and migrate users over.

JIRA: YANGTOOLS-846
Change-Id: I673ae6df4406110202b86329121a3ca9673fb0ed
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit e7e0e48e6a79b08bb2c976ee3fd69582d84a7e4c)

yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/IdentityrefJSONCodec.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java
yang/yang-data-codec-gson/src/test/resources/complexjson/case-node-augmentation-in-choice-in-container.json
yang/yang-data-codec-gson/src/test/resources/complexjson/case-node-external-augmentation-in-choice-in-container.json
yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/IdentityrefXmlCodec.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/codec/IdentityCodecUtil.java [new file with mode: 0644]
yang/yang-data-util/src/test/resources/yangtools846.yang [new file with mode: 0644]

index 50379d30984d317b2ec4064483be39c7d3b0513c..209093949b2a09374080b9e95237f48a4cf39f3b 100644 (file)
@@ -12,6 +12,7 @@ import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.util.codec.IdentityCodecUtil;
 import org.opendaylight.yangtools.yang.data.util.codec.QNameCodecUtil;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -32,7 +33,7 @@ final class IdentityrefJSONCodec implements JSONCodec<QName> {
 
     @Override
     public QName parseValue(final Object ctx, final String value) {
-        return QNameCodecUtil.decodeQName(value, prefix -> {
+        return IdentityCodecUtil.parseIdentity(value, schemaContext, prefix -> {
             if (prefix.isEmpty()) {
                 return parentModule;
             }
@@ -40,7 +41,7 @@ final class IdentityrefJSONCodec implements JSONCodec<QName> {
             final Module module = schemaContext.findModuleByName(prefix, null);
             Preconditions.checkArgument(module != null, "Could not find module %s", prefix);
             return module.getQNameModule();
-        });
+        }).getQName();
     }
 
     /**
index fb4a6986a5bf0f63ff1c67706a039e68fc579183..83f9b980707f63a988bd708dd6d16851e5f3f550 100644 (file)
@@ -229,7 +229,7 @@ public class NormalizedNodeToJsonStreamTest {
             assertEquals("lf15_21 value", lf15_21.getAsString());
             assertEquals("lf13 value", lf13.getAsString());
             assertTrue("one two".equals(lf15_11.getAsString()) || "two one".equals(lf15_11.getAsString()));
-            assertEquals("complexjson:lf11", lf15_12.getAsString());
+            assertEquals("complexjson:ident", lf15_12.getAsString());
 
         }).validate(jsonOutput);
     }
@@ -271,7 +271,7 @@ public class NormalizedNodeToJsonStreamTest {
             assertEquals("lf15_12 value from augmentation", lf15_12Augment.getAsString());
             assertEquals("lf13 value", lf13.getAsString());
             assertTrue("one two".equals(lf15_11.getAsString()) || "two one".equals(lf15_11.getAsString()));
-            assertEquals("complexjson:lf11", lf15_12.getAsString());
+            assertEquals("complexjson:ident", lf15_12.getAsString());
 
         }).validate(jsonOutput);
     }
index db4814c9820364919af8ba334fe5d31d5cb14708..c8d9d2c0b8c63cf453e069e529fc293f5e757102 100644 (file)
@@ -154,7 +154,7 @@ public class TestingNormalizedNodeStructuresCreator {
     private static LeafNode<Object> lf15_12Node() {
         return Builders.leafBuilder()
                 .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf15_12")))
-                .withValue(QName.create("ns:complex:json", "2014-08-11", "lf11")).build();
+                .withValue(QName.create("ns:complex:json", "2014-08-11", "ident")).build();
     }
 
     private static LeafNode<Object> lf15_11Node() {
index 8b771bc584c45565a49deccdab6bd1754a3b34f8..51f6e4c7e6dc177ec184ae8f5534e95b48a6ed93 100644 (file)
@@ -3,6 +3,6 @@
         "lf15_11" : "one two",        
         "lf13" : "lf13 value",        
         "lf15_21" : "lf15_21 value",
-        "lf15_12" : "complexjson:lf11"
+        "lf15_12" : "complexjson:ident"
     }
 }
index b15dce87d25f3be8a2e989d64caf6fe5c776ca7d..05cdd5715516ce5f3aee5e62b60ce6a18083d6df 100644 (file)
@@ -4,6 +4,6 @@
         "lf15_11" : "one two",        
         "lf13" : "lf13 value",        
         "complexjson-augmentation:lf15_12" : "lf15_12 value from augmentation",
-        "lf15_12" : "complexjson:lf11"
+        "lf15_12" : "complexjson:ident"
     }
 }
index 355e2c2cff44e7f9f4ab80f10e2fddc9975652d4..068a2bdda4f6cd371447f9bbca8f1334749b0fe9 100644 (file)
@@ -29,7 +29,7 @@
         "complexjson-augmentation:lf15_11" : "lf15_11 value from augmentation",
         "complexjson-augmentation:lf15_12" : "lf15_12 value from augmentation",
         "lf15_11" : "one two",
-        "lf15_12" : "complexjson:lf11",
+        "lf15_12" : "complexjson:ident",
         "lf15_21" : "lf15_21 value",
         "lf17" : "lf17 value",
 
index 378fef581a3af2e5cda0de284ef230ec824e7047..48deb4fcfce828a007db32430e29ce97bad4897b 100644 (file)
@@ -5,7 +5,6 @@
  * 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.data.codec.xml;
 
 import com.google.common.base.Preconditions;
@@ -16,6 +15,7 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.util.codec.IdentityCodecUtil;
 import org.opendaylight.yangtools.yang.data.util.codec.QNameCodecUtil;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -36,7 +36,7 @@ final class IdentityrefXmlCodec implements XmlCodec<QName> {
 
     @Override
     public QName parseValue(final NamespaceContext ctx, final String str) {
-        return QNameCodecUtil.decodeQName(str, prefix -> {
+        return IdentityCodecUtil.parseIdentity(str, schemaContext, prefix -> {
             if (prefix.isEmpty()) {
                 return parentModule;
             }
@@ -45,7 +45,7 @@ final class IdentityrefXmlCodec implements XmlCodec<QName> {
             final Module module = schemaContext.findModuleByNamespaceAndRevision(URI.create(prefixedNS), null);
             Preconditions.checkArgument(module != null, "Could not find module for namespace %s", prefixedNS);
             return module.getQNameModule();
-        });
+        }).getQName();
     }
 
     @Override
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/codec/IdentityCodecUtil.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/codec/IdentityCodecUtil.java
new file mode 100644 (file)
index 0000000..660cbae
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.data.util.codec;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.Beta;
+import java.util.function.Function;
+import javax.annotation.concurrent.ThreadSafe;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Utility methods for implementing string-to-identity codecs.
+ *
+ * @author Robert Varga
+ */
+@Beta
+@NonNullByDefault
+@ThreadSafe
+public final class IdentityCodecUtil {
+
+    private IdentityCodecUtil() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Parse a string into a QName using specified prefix-to-QNameModule mapping function, interpreting the result
+     * as an IdentitySchemaNode existing in specified SchemaContext.
+     *
+     * @param value string value to parse
+     * @param schemaContext Parent schema context
+     * @param prefixToModule prefix-to-QNameModule mapping function
+     * @return Corresponding IdentitySchemaNode.
+     * @throws IllegalArgumentException if the value is invalid or does not refer to an existing identity
+     */
+    public static IdentitySchemaNode parseIdentity(final String value, final SchemaContext schemaContext,
+            final Function<String, QNameModule> prefixToModule) {
+        final QName qname = QNameCodecUtil.decodeQName(value, prefixToModule);
+        final Module module = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(),
+            qname.getRevision());
+        checkState(module != null, "Parsed QName %s refers to a non-existent module", qname);
+
+        for (IdentitySchemaNode identity : module.getIdentities()) {
+            if (qname.equals(identity.getQName())) {
+                return identity;
+            }
+        }
+
+        throw new IllegalArgumentException("Parsed QName " + qname + " does not refer to a valid identity");
+    }
+}
diff --git a/yang/yang-data-util/src/test/resources/yangtools846.yang b/yang/yang-data-util/src/test/resources/yangtools846.yang
new file mode 100644 (file)
index 0000000..4e577c8
--- /dev/null
@@ -0,0 +1,7 @@
+module yangtools846 {
+    namespace "yangtools846";
+    prefix yt846;
+
+    identity foo;
+}
+