/* * 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.data.util; import static java.util.Objects.requireNonNull; import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.Mutable; 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; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; /** * Iterator which lazily parses {@link PathArgument} from string representation. * *
* 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.
*/
final class XpathStringParsingPathArgumentBuilder implements Mutable {
/**
* Matcher matching WSP YANG ABNF token.
*/
private static final CharMatcher WSP = CharMatcher.anyOf(" \t");
/**
* Matcher matching IDENTIFIER first char token.
*/
private static final CharMatcher IDENTIFIER_FIRST_CHAR = CharMatcher.inRange('a', 'z')
.or(CharMatcher.inRange('A', 'Z')).or(CharMatcher.is('_')).precomputed();
/**
* Matcher matching IDENTIFIER token.
*/
private static final CharMatcher IDENTIFIER = IDENTIFIER_FIRST_CHAR.or(CharMatcher.inRange('0', '9'))
.or(CharMatcher.anyOf(".-")).precomputed();
private static final CharMatcher QUOTE = CharMatcher.anyOf("'\"");
private static final char SLASH = '/';
private static final char COLON = ':';
private static final char DOT = '.';
private static final char EQUALS = '=';
private static final char PRECONDITION_START = '[';
private static final char PRECONDITION_END = ']';
private final List
* 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.
*/
private void checkValid(final boolean condition, final String errorMsg, final Object... attributes) {
if (!condition) {
throw new IllegalArgumentException(String.format(
"Could not parse Instance Identifier '%s'. Offset: %s : Reason: %s", data, offset,
String.format(errorMsg, attributes)));
}
}
/**
* Returns following value of quoted literal (without quotes) and sets offset after literal.
*
* @return String literal
*/
private String nextQuotedValue() {
final char quoteChar = currentChar();
checkValid(QUOTE.matches(quoteChar), "Value must be qoute escaped with ''' or '\"'.");
skipCurrentChar();
final int valueStart = offset;
final int endQoute = data.indexOf(quoteChar, offset);
final String value = data.substring(valueStart, endQoute);
offset = endQoute;
skipCurrentChar();
return value;
}
/**
* Returns character at current offset.
*
* @return character at current offset.
*/
private char currentChar() {
return data.charAt(offset);
}
/**
* Increases processing offset by 1.
*/
private void skipCurrentChar() {
offset++;
}
/**
* Skip whitespace characters, sets offset to first following non-whitespace character.
*/
private void skipWhitespaces() {
nextSequenceEnd(WSP);
}
/**
* Returns string which matches IDENTIFIER YANG ABNF token
* and sets processing offset after end of identifier.
*
* @return string which matches IDENTIFIER YANG ABNF token
*/
private String nextIdentifier() {
checkValid(IDENTIFIER_FIRST_CHAR.matches(currentChar()),
"Identifier must start with character from set 'a-zA-Z_'");
final int start = offset;
nextSequenceEnd(IDENTIFIER);
return data.substring(start, offset);
}
private void nextSequenceEnd(final CharMatcher matcher) {
while (!allCharactersConsumed() && matcher.matches(data.charAt(offset))) {
offset++;
}
}
}