Validate parsed QName to identity
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / XpathStringParsingPathArgumentBuilder.java
index 5141d623ba9fa683f4cb787cbabc5e9ed51a4e52..a2a21da1978a8e9feb7ed1cbd105b2f47a0ab328 100644 (file)
@@ -7,15 +7,16 @@
  */
 package org.opendaylight.yangtools.yang.data.util;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.base.CharMatcher;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@@ -23,15 +24,16 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum
 /**
  * Iterator which lazily parses {@link PathArgument} from string representation.
  *
+ * <p>
  * Note that invocation of {@link #hasNext()} or {@link #next()} may result in
  * throwing of {@link IllegalArgumentException} if underlying string representation
  * is not correctly serialized or does not represent instance identifier valid
  * for associated schema context.
  */
-class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathArgument>> {
+final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathArgument>> {
 
     /**
-     * Matcher matching WSP YANG ABNF token
+     * Matcher matching WSP YANG ABNF token.
      */
     private static final CharMatcher WSP = CharMatcher.anyOf(" \t");
 
@@ -42,7 +44,7 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
             .or(CharMatcher.inRange('A', 'Z')).or(CharMatcher.is('_')).precomputed();
 
     /**
-     * Matcher matching IDENTIFIER token
+     * Matcher matching IDENTIFIER token.
      */
     private static final CharMatcher IDENTIFIER = IDENTIFIER_FIRST_CHAR.or(CharMatcher.inRange('0', '9'))
             .or(CharMatcher.anyOf(".-")).precomputed();
@@ -56,23 +58,23 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
     private static final char PRECONDITION_START = '[';
     private static final char PRECONDITION_END = ']';
 
+    private final List<PathArgument> product = new ArrayList<>();
     private final AbstractStringInstanceIdentifierCodec codec;
     private final String data;
 
-    private final List<PathArgument> product = new ArrayList<>();
-
     private DataSchemaContextNode<?> current;
+    private QNameModule lastModule;
     private int offset;
 
     XpathStringParsingPathArgumentBuilder(final AbstractStringInstanceIdentifierCodec codec, final String data) {
-        this.codec = Preconditions.checkNotNull(codec);
-        this.data = Preconditions.checkNotNull(data);
+        this.codec = requireNonNull(codec);
+        this.data = requireNonNull(data);
         this.current = codec.getDataContextTree().getRoot();
         this.offset = 0;
     }
 
     @Override
-    public Collection<PathArgument> build() {
+    public List<PathArgument> build() {
         while (!allCharactersConsumed()) {
             product.add(computeNextArgument());
         }
@@ -83,7 +85,9 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
         checkValid(SLASH == currentChar(), "Identifier must start with '/'.");
         skipCurrentChar();
         checkValid(!allCharactersConsumed(), "Identifier cannot end with '/'.");
-        QName name = nextQName();
+        final QName name = nextQName();
+        // Memoize module
+        lastModule = name.getModule();
         if (allCharactersConsumed() || SLASH == currentChar()) {
             return computeIdentifier(name);
         }
@@ -167,26 +171,19 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
     private QName nextQName() {
         // Consume prefix or identifier
         final String maybePrefix = nextIdentifier();
-        final String prefix;
-        final String localName;
-        if (COLON == currentChar()) {
-            // previous token is prefix;
-            prefix = maybePrefix;
+        if (!allCharactersConsumed() && COLON == currentChar()) {
+            // previous token is prefix
             skipCurrentChar();
-            localName = nextIdentifier();
-        } else {
-            prefix = "";
-            localName = maybePrefix;
+            return codec.createQName(maybePrefix, nextIdentifier());
         }
-        return codec.createQName(prefix, localName);
+
+        return codec.createQName(lastModule, maybePrefix);
     }
 
     /**
-     * Returns true if all characters from input string
-     * were consumed.
+     * Returns true if all characters from input string were consumed.
      *
-     * @return true if all characters from input string
-     * were consumed.
+     * @return true if all characters from input string were consumed.
      */
     private boolean allCharactersConsumed() {
         return offset == data.length();
@@ -206,12 +203,12 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
     /**
      * Fails parsing if a condition is not met.
      *
+     * <p>
      * In case of error provides pointer to failed instance identifier,
      * offset on which failure occurred with explanation.
      *
      * @param condition Fails parsing if {@code condition} is false
      * @param errorMsg Error message which will be provided to user.
-     * @param attributes
      */
     private void checkValid(final boolean condition, final String errorMsg, final Object... attributes) {
         if (!condition) {
@@ -248,15 +245,14 @@ class XpathStringParsingPathArgumentBuilder implements Builder<Collection<PathAr
     }
 
     /**
-     * Increases processing offset by 1
+     * Increases processing offset by 1.
      */
     private void skipCurrentChar() {
         offset++;
     }
 
     /**
-     * Skip whitespace characters, sets offset to first following
-     * non-whitespace character.
+     * Skip whitespace characters, sets offset to first following non-whitespace character.
      */
     private void skipWhitespaces() {
         nextSequenceEnd(WSP);