Add QName.create(String). 16/4716/3
authorTony Tkacik <ttkacik@cisco.com>
Sat, 25 Jan 2014 11:53:19 +0000 (12:53 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Sat, 25 Jan 2014 11:53:29 +0000 (12:53 +0100)
Add mechanism for deserialization from QName.toString().
Add basic validation to local name.

Change-Id: I84babfe169c5c6195cd431a63558da621966b54c
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
yang/yang-common/pom.xml
yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/QName.java
yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/QNameTest.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/MyNodeBuilder.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/NodeFactoryTest.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java
yang/yang-parser-impl/src/test/resources/augment-test/augment-in-augment/baz.yang
yang/yang-parser-impl/src/test/resources/model/baz.yang

index f126e528e33c0ef20c4b60a31e2fce33d9958d7d..c6026aea9b52797cba169019c950647c726131ee 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>concepts</artifactId>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
index 01b20a3b540d4392235c308eead1934a51569c43..faa0324ea55df1bee8b5ddddabd452537fde71cf 100644 (file)
@@ -14,11 +14,12 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.opendaylight.yangtools.yang.common.QName;
 
 /**
  * The QName from XML consists of local name of element and XML namespace, but
@@ -57,11 +58,20 @@ public final class QName implements Immutable,Serializable {
         };
 
     };
+    static final String QNAME_REVISION_DELIMITER = "?revision=";
+    static final String QNAME_LEFT_PARENTHESIS = "(";
+    static final String QNAME_RIGHT_PARENTHESIS = ")";
 
+
+    //Nullable
     private final URI namespace;
+    //Mandatory
     private final String localName;
+    //Nullable
     private final String prefix;
+    //Nullable
     private final String formattedRevision;
+    //Nullable
     private final Date revision;
 
     /**
@@ -77,8 +87,8 @@ public final class QName implements Immutable,Serializable {
      *            YANG schema identifier
      */
     public QName(URI namespace, Date revision, String prefix, String localName) {
+        this.localName = checkLocalName(localName);
         this.namespace = namespace;
-        this.localName = localName;
         this.revision = revision;
         this.prefix = prefix;
         if(revision != null) {
@@ -100,6 +110,21 @@ public final class QName implements Immutable,Serializable {
         this(namespace, null, "", localName);
     }
 
+    private static String checkLocalName(String localName) {
+        if (localName == null || localName.length() == 0) {
+            throw new IllegalArgumentException("Parameter 'localName' must be non empty string.");
+        }
+        String [] illegalSubstrings = new String[] {"?", "(", ")", "&"};
+        for(String illegalSubstring: illegalSubstrings) {
+            if (localName.contains(illegalSubstring)) {
+                throw new IllegalArgumentException(String.format(
+                        "Parameter 'localName':'%s' contains illegal sequence '%s'",
+                        localName, illegalSubstring));
+            }
+        }
+        return localName;
+    }
+
     /**
      * QName Constructor.
      *
@@ -118,10 +143,14 @@ public final class QName implements Immutable,Serializable {
         this(base.getNamespace(), base.getRevision(), base.getPrefix(), localName);
     }
 
-    // TODO: rework with pattern
-    public QName(String base) throws ParseException {
+    /**
+     * @deprecated Use {@link #create(String)} instead.
+     * This implementation is broken.
+     */
+    @Deprecated
+    public QName(String input) throws ParseException {
         Date revision = null;
-        String nsAndRev = base.substring(base.indexOf("(") + 1, base.indexOf(")"));
+        String nsAndRev = input.substring(input.indexOf("(") + 1, input.indexOf(")"));
         if (nsAndRev.contains("?")) {
             String[] splitted = nsAndRev.split("\\?");
             this.namespace = URI.create(splitted[0]);
@@ -130,7 +159,7 @@ public final class QName implements Immutable,Serializable {
             this.namespace = URI.create(nsAndRev);
         }
 
-        this.localName = base.substring(base.indexOf(")") + 1);
+        this.localName = checkLocalName(input.substring(input.indexOf(")") + 1));
         this.revision = revision;
         this.prefix = null;
         if (revision != null) {
@@ -140,6 +169,36 @@ public final class QName implements Immutable,Serializable {
         }
     }
 
+
+    private static Pattern QNAME_PATTERN_FULL = Pattern.compile(
+            "^\\((.+)\\" + QNAME_REVISION_DELIMITER + "(.+)\\)(.+)$");
+    private static Pattern QNAME_PATTERN_NO_REVISION = Pattern.compile(
+           "^\\((.+)\\)(.+)$" );
+    private static Pattern QNAME_PATTERN_NO_NAMESPACE_NO_REVISION = Pattern.compile(
+            "^(.+)$" );
+
+    public static QName create(String input) {
+        Matcher matcher = QNAME_PATTERN_FULL.matcher(input);
+        if (matcher.matches()) {
+            String namespace = matcher.group(1);
+            String revision = matcher.group(2);
+            String localName = matcher.group(3);
+            return create(namespace, revision, localName);
+        }
+        matcher = QNAME_PATTERN_NO_REVISION.matcher(input);
+        if (matcher.matches()) {
+            URI namespace = URI.create(matcher.group(1));
+            String localName = matcher.group(2);
+            return new QName(namespace, localName);
+        }
+        matcher = QNAME_PATTERN_NO_NAMESPACE_NO_REVISION.matcher(input);
+        if (matcher.matches()) {
+            String localName = matcher.group(1);
+            return new QName((URI)null, localName);
+        }
+        throw new IllegalArgumentException("Invalid input:" + input);
+    }
+
     /**
      * Returns XMLNamespace assigned to the YANG module.
      *
@@ -250,12 +309,12 @@ public final class QName implements Immutable,Serializable {
     public String toString() {
         StringBuilder sb = new StringBuilder();
         if (namespace != null) {
-            sb.append("(" + namespace);
+            sb.append(QNAME_LEFT_PARENTHESIS + namespace);
 
             if (revision != null) {
-                sb.append("?revision=" + REVISION_FORMAT.get().format(revision));
+                sb.append(QNAME_REVISION_DELIMITER + REVISION_FORMAT.get().format(revision));
             }
-            sb.append(")");
+            sb.append(QNAME_RIGHT_PARENTHESIS);
         }
         sb.append(localName);
         return sb.toString();
@@ -304,8 +363,8 @@ public final class QName implements Immutable,Serializable {
     public static Date parseRevision(String formatedDate) {
         try {
             return REVISION_FORMAT.get().parse(formatedDate);
-        } catch (ParseException e) {
-            throw new IllegalArgumentException("Revision is not in supported format",e);
+        } catch (ParseException| RuntimeException e) {
+            throw new IllegalArgumentException("Revision is not in supported format:" + formatedDate,e);
         }
     }
 
diff --git a/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/QNameTest.java b/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/QNameTest.java
new file mode 100644 (file)
index 0000000..23ca2ee
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 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.common;
+
+import org.junit.Test;
+
+import java.net.URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class QNameTest {
+    private final String namespace = "urn:foo", revision = "2013-12-24", localName = "bar";
+    private final URI ns;
+
+    public QNameTest() throws Exception {
+        this.ns = new URI(namespace);
+    }
+
+    @Test
+    public void testStringSerialization() throws Exception {
+        {
+            QName qName = QName.create(namespace, revision, localName);
+            assertEquals(QName.QNAME_LEFT_PARENTHESIS + namespace + QName.QNAME_REVISION_DELIMITER
+                    + revision + QName.QNAME_RIGHT_PARENTHESIS + localName, qName.toString());
+            QName copied = QName.create(qName.toString());
+            assertEquals(qName, copied);
+        }
+        // no revision
+        {
+            QName qName = new QName(ns, localName);
+            assertEquals(QName.QNAME_LEFT_PARENTHESIS + namespace + QName.QNAME_RIGHT_PARENTHESIS
+                    + localName, qName.toString());
+            QName copied = QName.create(qName.toString());
+            assertEquals(qName, copied);
+        }
+        // no namespace nor revision
+        {
+            QName qName = new QName((URI) null, localName);
+            assertEquals(localName, qName.toString());
+            QName copied = QName.create(qName.toString());
+            assertEquals(qName, copied);
+        }
+    }
+
+    @Test
+    public void testIllegalLocalNames() {
+        assertLocalNameFails(null);
+        assertLocalNameFails("");
+        assertLocalNameFails("(");
+        assertLocalNameFails(")");
+        assertLocalNameFails("?");
+        assertLocalNameFails("&");
+    }
+
+    private void assertLocalNameFails(String localName) {
+        try {
+            new QName((URI)null, localName);
+            fail("Local name should fail:" + localName);
+        } catch (IllegalArgumentException e) {
+
+        }
+    }
+
+}
index 90d75c0b82f0e472cef9e9087dce047b55a8993e..16f57cbbe60d45d346288401a9aeab84c6cb7e48 100644 (file)
@@ -56,7 +56,7 @@ public class MyNodeBuilder extends BuilderSupport {
        try {\r
                        qName = new QName(\r
                        new URI("urn:opendaylight:controller:network"),\r
-                       new Date(42), "yang-data-impl-groovyTest_", null);\r
+                       new Date(42), "yang-data-impl-groovyTest_", "node");\r
         } catch (URISyntaxException e) {\r
                LOG.error(e.getMessage(), e);\r
         }\r
index 32611bb3b690389923b3ecf5767dc55b58a6efb9..fc60b826ee4b276460f28c1988b3da61ae90fbdf 100644 (file)
@@ -47,7 +47,7 @@ public class NodeFactoryTest {
         ns = "urn:ietf:params:xml:ns:netconf:base:1.0";\r
         qName = new QName(\r
                 new URI(ns),\r
-                new Date(42), null);\r
+                new Date(42), "node");\r
         network = NodeHelper.buildTestConfigTree(qName);\r
         networkShadow = NodeUtils.buildShadowDomTree(network);\r
         NodeHelper.compareXmlTree(networkShadow, "./config02-shadow.xml", getClass());\r
index 86ddd4bdd66fcc0c2dc875afe6430cff75d7af45..648bc121e1ea19ab4786f66ef3cfe49d7b7154f2 100644 (file)
@@ -190,6 +190,7 @@ public final class YangParserImpl implements YangModelParser {
         final Map<InputStream, File> inputStreams = new HashMap<>();
         for (final File yangFile : yangFiles) {
             try {
+                
                 inputStreams.put(new FileInputStream(yangFile), yangFile);
             } catch (FileNotFoundException e) {
                 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
index 92d583f81c24df1b6cb418ae8e66b94f40fbc4d2..a90982e0e659ff49aea3dda6780cf8ca8e230c26 100644 (file)
@@ -56,6 +56,8 @@ import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Strings;
+
 public final class YangParserListenerImpl extends YangParserBaseListener {
     private static final Logger LOGGER = LoggerFactory.getLogger(YangParserListenerImpl.class);
     private static final String AUGMENT_STR = "augment";
@@ -795,8 +797,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
             nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]);
         }
 
-        QName qname;
-        if (nodeParameter != null) {
+        QName qname = null;
+        if (!Strings.isNullOrEmpty(nodeParameter)) {
             String[] splittedName = nodeParameter.split(":");
             if (splittedName.length == 2) {
                 qname = new QName(null, null, splittedName[0], splittedName[1]);
@@ -804,10 +806,9 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
                 qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
             }
         } else {
-            qname = new QName(namespace, revision, yangModelPrefix, nodeParameter);
+            qname = nodeType;
         }
-
-        addNodeToPath(new QName(namespace, revision, yangModelPrefix, nodeParameter));
+        addNodeToPath(qname);
         SchemaPath path = createActualSchemaPath(actualPath.peek());
 
         UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
index eced11f8375560a5bdef99067b976701749d9998..f50c46130a5925c63f54021d7a1f58ea2297e989 100644 (file)
@@ -87,8 +87,8 @@ module baz {
                 type int8;
             }
         }
-
-        opendaylight;
+        
+        br:opendaylight;
     }
 
 }
index ec8a6f752ea8834f57536c1f280e82217ed67bfc..e1dee2d002c88e9042385cbf99bf9e3327e45eea 100644 (file)
@@ -187,8 +187,8 @@ module baz {
         typedef group-type {
             type br:my-decimal-type;
         }
-
-        opendaylight;
+        
+        br:opendaylight;
     }
 
 }