import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.CharMatcher;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import java.io.DataInput;
import org.opendaylight.yangtools.concepts.WritableObject;
/**
- * The QName from XML consists of local name of element and XML namespace, but
- * for our use, we added module revision to it.
+ * The QName from XML consists of local name of element and XML namespace, but for our use, we added module revision to
+ * it.
*
* <p>
- * In YANG context QName is full name of defined node, type, procedure or
- * notification. QName consists of XML namespace, YANG model revision and local
- * name of defined type. It is used to prevent name clashes between nodes with
- * same local name, but from different schemas.
+ * In YANG context QName is full name of defined node, type, procedure or notification. QName consists of XML namespace,
+ * YANG model revision and local name of defined type. It is used to prevent name clashes between nodes with same local
+ * name, but from different schemas.
+ *
+ * <p>
+ * The local name must conform to <a href="https://tools.ietf.org/html/rfc7950#section-6.2">RFC7950 Section 6.2</a>.
*
* <ul>
* <li><b>XMLNamespace</b> - {@link #getNamespace()} - the namespace assigned to the YANG module which
* <li><b>LocalName</b> - {@link #getLocalName()} - the YANG schema identifier which were defined for this
* node in the YANG module</li>
* </ul>
- *
- * <p>
- * QName may also have <code>prefix</code> assigned, but prefix does not
- * affect equality and identity of two QNames and carry only information
- * which may be useful for serializers / deserializers.
*/
public final class QName implements Immutable, Serializable, Comparable<QName>, Identifier, WritableObject {
private static final Interner<QName> INTERNER = Interners.newWeakInterner();
private static final String QNAME_STRING_NO_REVISION = "^\\((.+)\\)(.+)$";
private static final Pattern QNAME_PATTERN_NO_REVISION = Pattern.compile(QNAME_STRING_NO_REVISION);
- private static final char[] ILLEGAL_CHARACTERS = { '?', '(', ')', '&', ':' };
+ private static final CharMatcher IDENTIFIER_START =
+ CharMatcher.inRange('A', 'Z').or(CharMatcher.inRange('a', 'z').or(CharMatcher.is('_'))).precomputed();
+ private static final CharMatcher NOT_IDENTIFIER_PART =
+ IDENTIFIER_START.or(CharMatcher.inRange('0', '9')).or(CharMatcher.anyOf("-.")).negate().precomputed();
private final @NonNull QNameModule module;
private final @NonNull String localName;
private static @NonNull String checkLocalName(final String localName) {
checkArgument(localName != null, "Parameter 'localName' may not be null.");
checkArgument(!localName.isEmpty(), "Parameter 'localName' must be a non-empty string.");
-
- for (final char c : ILLEGAL_CHARACTERS) {
- if (localName.indexOf(c) != -1) {
- throw new IllegalArgumentException("Parameter 'localName':'" + localName
- + "' contains illegal character '" + c + "'");
- }
- }
+ checkArgument(IDENTIFIER_START.matches(localName.charAt(0)) && NOT_IDENTIFIER_PART.indexIn(localName, 1) == -1,
+ "String '%s' is not a valid identifier", localName);
return localName;
}
final URI uriB1 = new URI("some:uriB1");
final URI uriB2 = new URI("some:uriB2");
- QName qnameA1 = QName.create(uriA1, Revision.of("2000-01-01"), "some nameA1");
- QName qnameA2 = QName.create(uriA2, Revision.of("2002-01-01"), "some nameA2");
+ QName qnameA1 = QName.create(uriA1, Revision.of("2000-01-01"), "someNameA1");
+ QName qnameA2 = QName.create(uriA2, Revision.of("2002-01-01"), "someNameA2");
SchemaPath schemaPathA = SchemaPath.create(true, qnameA1, qnameA2);
- final QName qnameB1 = QName.create(uriB1, Revision.of("2000-01-01"), "some nameB1");
- final QName qnameB2 = QName.create(uriB2, Revision.of("2002-01-01"), "some nameB2");
+ final QName qnameB1 = QName.create(uriB1, Revision.of("2000-01-01"), "someNameB1");
+ final QName qnameB2 = QName.create(uriB2, Revision.of("2002-01-01"), "someNameB2");
final SchemaPath schemaPathB = SchemaPath.create(true, qnameB1, qnameB2);
BitImpl biA = new BitImpl(schemaPathA, 55L, "description", "reference", Status.CURRENT, emptyList());
assertEquals("Incorrect value for unknown nodes.", emptyList(), biA.getUnknownSchemaNodes());
// test of toString method
- assertEquals("toString method doesn't return correct value", "Bit[name=some nameA2, position=55]",
+ assertEquals("toString method doesn't return correct value", "Bit[name=someNameA2, position=55]",
biA.toString());
}
}
import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.UnknownEffectiveStatementBase;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
final class UnrecognizedEffectiveStatementImpl extends UnknownEffectiveStatementBase<String, UnrecognizedStatement>
implements UnrecognizedEffectiveStatement {
+ private static final Logger LOG = LoggerFactory.getLogger(UnrecognizedEffectiveStatementImpl.class);
private final QName maybeQNameArgument;
private final @NonNull SchemaPath path;
QName maybeQNameArgumentInit = null;
try {
maybeQNameArgumentInit = StmtContextUtils.qnameFromArgument(ctx, argument());
- } catch (IllegalArgumentException e) {
+ } catch (SourceException e) {
+ LOG.debug("Not constructing QName from {}", argument(), e);
maybeQNameArgumentInit = getNodeType();
}
this.maybeQNameArgument = maybeQNameArgumentInit;
fail("Test should fail due to invalid Yang 1.0");
} catch (final SomeModifiersUnresolvedException e) {
assertTrue(e.getCause().getMessage()
- .startsWith("String '(not foo) or (bar and baz)' is not a valid identifier "));
+ .startsWith("Invalid identifier '(not foo) or (bar and baz)' [at "));
}
}
}
\ No newline at end of file
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
-import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
public final class StmtContextUtils {
- private static final CharMatcher IDENTIFIER_START =
- CharMatcher.inRange('A', 'Z').or(CharMatcher.inRange('a', 'z').or(CharMatcher.is('_'))).precomputed();
- private static final CharMatcher NOT_IDENTIFIER_PART =
- IDENTIFIER_START.or(CharMatcher.inRange('0', '9')).or(CharMatcher.anyOf("-.")).negate().precomputed();
-
private StmtContextUtils() {
throw new UnsupportedOperationException("Utility class");
}
public static QName parseIdentifier(final StmtContext<?, ?, ?> ctx, final String str) {
SourceException.throwIf(str.isEmpty(), ctx.getStatementSourceReference(),
"Identifier may not be an empty string");
- checkIdentifierString(ctx, str);
return internedQName(ctx, str);
}
final int colon = str.indexOf(':');
if (colon == -1) {
- checkIdentifierString(ctx, str);
return internedQName(ctx, str);
}
final String localName = str.substring(colon + 1);
SourceException.throwIf(localName.isEmpty(), ctx.getStatementSourceReference(),
"String '%s' has an empty identifier", str);
- checkIdentifierString(ctx, localName);
final QNameModule module = StmtContextUtils.getModuleQNameByPrefix(ctx, prefix);
if (module != null) {
throw new InferenceException(ctx.getStatementSourceReference(), "Cannot resolve QNameModule for '%s'", str);
}
- private static void checkIdentifierString(final StmtContext<?, ?, ?> ctx, final String str) {
- SourceException.throwIf(!IDENTIFIER_START.matches(str.charAt(0)) || NOT_IDENTIFIER_PART.indexIn(str, 1) != -1,
- ctx.getStatementSourceReference(), "String '%s' is not a valid identifier", str);
- }
-
private static QName internedQName(final StmtContext<?, ?, ?> ctx, final String localName) {
return internedQName(ctx, StmtContextUtils.getRootModuleQName(ctx), localName);
}
private static QName internedQName(final StmtContext<?, ?, ?> ctx, final QNameModule module,
final String localName) {
- return ctx.getFromNamespace(QNameCacheNamespace.class, QName.create(module, localName));
+ final QName template;
+ try {
+ template = QName.create(module, localName);
+ } catch (IllegalArgumentException e) {
+ throw new SourceException(ctx.getStatementSourceReference(), e, "Invalid identifier '%s'", localName);
+ }
+
+ return ctx.getFromNamespace(QNameCacheNamespace.class, template);
}
public static QNameModule getRootModuleQName(final StmtContext<?, ?, ?> ctx) {