*/
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;
/**
* 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");
.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();
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());
}
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);
}
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();
/**
* 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) {
}
/**
- * 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);