public final class Utils {
private static final int UNICODE_SCRIPT_FIX_COUNTER = 30;
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
- private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
- private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
private static final CharMatcher LEFT_PARENTHESIS_MATCHER = CharMatcher.is('(');
private static final CharMatcher RIGHT_PARENTHESIS_MATCHER = CharMatcher.is(')');
private static final CharMatcher AMPERSAND_MATCHER = CharMatcher.is('&');
private static final Map<String, Deviate> KEYWORD_TO_DEVIATE_MAP;
static {
- Builder<String, Deviate> keywordToDeviateMapBuilder = ImmutableMap.builder();
- for (Deviate deviate : Deviation.Deviate.values()) {
+ final Builder<String, Deviate> keywordToDeviateMapBuilder = ImmutableMap.builder();
+ for (final Deviate deviate : Deviation.Deviate.values()) {
keywordToDeviateMapBuilder.put(deviate.getKeyword(), deviate);
}
KEYWORD_TO_DEVIATE_MAP = keywordToDeviateMapBuilder.build();
public static Collection<SchemaNodeIdentifier.Relative> transformKeysStringToKeyNodes(final StmtContext<?, ?, ?> ctx,
final String value) {
- List<String> keyTokens = SPACE_SPLITTER.splitToList(value);
+ final List<String> keyTokens = SPACE_SPLITTER.splitToList(value);
// to detect if key contains duplicates
if ((new HashSet<>(keyTokens)).size() < keyTokens.size()) {
throw new SourceException(ctx.getStatementSourceReference(), "Duplicate value in list key: %s", value);
}
- Set<SchemaNodeIdentifier.Relative> keyNodes = new HashSet<>();
+ final Set<SchemaNodeIdentifier.Relative> keyNodes = new HashSet<>();
- for (String keyToken : keyTokens) {
+ for (final String keyToken : keyTokens) {
- SchemaNodeIdentifier.Relative keyNode = (Relative) SchemaNodeIdentifier.Relative.create(false,
+ final SchemaNodeIdentifier.Relative keyNode = (Relative) SchemaNodeIdentifier.Relative.create(false,
Utils.qNameFromArgument(ctx, keyToken));
keyNodes.add(keyNode);
}
try {
// TODO: we could capture the result and expose its 'evaluate' method
xPath.compile(trimmed);
- } catch (XPathExpressionException e) {
+ } catch (final XPathExpressionException e) {
LOG.warn("Argument \"{}\" is not valid XPath string at \"{}\"", path, ctx.getStatementSourceReference(), e);
}
}
public static QName trimPrefix(final QName identifier) {
- String prefixedLocalName = identifier.getLocalName();
- String[] namesParts = prefixedLocalName.split(":");
+ final String prefixedLocalName = identifier.getLocalName();
+ final String[] namesParts = prefixedLocalName.split(":");
if (namesParts.length == 2) {
- String localName = namesParts[1];
+ final String localName = namesParts[1];
return QName.create(identifier.getModule(), localName);
}
if (stmtDef.get(identifier) != null) {
return stmtDef.get(identifier).getStatementName();
} else {
- String prefixedLocalName = identifier.getLocalName();
- String[] namesParts = prefixedLocalName.split(":");
+ final String prefixedLocalName = identifier.getLocalName();
+ final String[] namesParts = prefixedLocalName.split(":");
if (namesParts.length == 2) {
- String prefix = namesParts[0];
- String localName = namesParts[1];
+ final String prefix = namesParts[0];
+ final String localName = namesParts[1];
if (prefixes != null && prefixes.get(prefix) != null
&& stmtDef.get(QName.create(prefixes.get(prefix), localName)) != null) {
return QName.create(prefixes.get(prefix), localName);
static SchemaNodeIdentifier nodeIdentifierFromPath(final StmtContext<?, ?, ?> ctx, final String path) {
// FIXME: is the path trimming really necessary??
final List<QName> qNames = new ArrayList<>();
- for (String nodeName : SLASH_SPLITTER.split(trimSingleLastSlashFromXPath(path))) {
+ for (final String nodeName : SLASH_SPLITTER.split(trimSingleLastSlashFromXPath(path))) {
try {
final QName qName = Utils.qNameFromArgument(ctx, nodeName);
qNames.add(qName);
- } catch (Exception e) {
+ } catch (final Exception e) {
throw new IllegalArgumentException(
String.format("Failed to parse node '%s' in path '%s'", nodeName, path), e);
}
}
public static String stringFromStringContext(final YangStatementParser.ArgumentContext context) {
- StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
List<TerminalNode> strings = context.STRING();
if (strings.isEmpty()) {
strings = Arrays.asList(context.IDENTIFIER());
}
- for (TerminalNode stringNode : strings) {
+ for (final TerminalNode stringNode : strings) {
final String str = stringNode.getText();
- char firstChar = str.charAt(0);
- final CharMatcher quoteMatcher;
- if (SINGLE_QUOTE_MATCHER.matches(firstChar)) {
- quoteMatcher = SINGLE_QUOTE_MATCHER;
- } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
- quoteMatcher = DOUBLE_QUOTE_MATCHER;
+ final char firstChar = str.charAt(0);
+ final char lastChar = str.charAt(str.length() - 1);
+ if (firstChar == '"' && lastChar == '"') {
+ final String innerStr = str.substring(1, str.length() - 1);
+ /*
+ * Unescape escaped double quotes, tabs, new line and backslash
+ * in the inner string and trim the result.
+ */
+ sb.append(innerStr.replace("\\\"", "\"").replace("\\\\", "\\").replace("\\n", "\n")
+ .replace("\\t", "\t"));
+ } else if (firstChar == '\'' && lastChar == '\'') {
+ /*
+ * According to RFC6020 a single quote character cannot occur in
+ * a single-quoted string, even when preceded by a backslash.
+ */
+ sb.append(str.substring(1, str.length() - 1));
} else {
sb.append(str);
- continue;
}
- sb.append(quoteMatcher.removeFrom(str.substring(1, str.length() - 1)));
}
return sb.toString();
}
QNameModule qNameModule = null;
String localName = null;
- String[] namesParts = value.split(":");
+ final String[] namesParts = value.split(":");
switch (namesParts.length) {
case 1:
localName = namesParts[0];
final QNameModule qNameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class, modId);
if (qNameModule == null && StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
- String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix);
+ final String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix);
return ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
}
return qNameModule;
public static Date getLatestRevision(final Iterable<? extends StmtContext<?, ?, ?>> subStmts) {
Date revision = null;
- for (StmtContext<?, ?, ?> subStmt : subStmts) {
+ for (final StmtContext<?, ?, ?> subStmt : subStmts) {
if (subStmt.getPublicDefinition().getDeclaredRepresentationClass().isAssignableFrom(RevisionStatement
.class)) {
if (revision == null && subStmt.getStatementArgument() != null) {
try {
Pattern.compile(rawPattern);
return rawPattern;
- } catch(PatternSyntaxException ex) {
+ } catch(final PatternSyntaxException ex) {
LOG.debug("Invalid regex pattern syntax in: {}", rawPattern, ex);
if (ex.getMessage().contains("Unknown character script name")) {
rawPattern = fixUnknownScripts(ex.getMessage(), rawPattern);
private static String fixUnknownScripts(final String exMessage, final String rawPattern) {
StringBuilder result = new StringBuilder(rawPattern);
- Matcher matcher = BETWEEN_CURLY_BRACES_PATTERN.matcher(exMessage);
+ final Matcher matcher = BETWEEN_CURLY_BRACES_PATTERN.matcher(exMessage);
if (matcher.find()) {
- String capturedGroup = matcher.group(1);
+ final String capturedGroup = matcher.group(1);
if (JAVA_UNICODE_BLOCKS.contains(capturedGroup)) {
- int idx = rawPattern.indexOf("Is" + capturedGroup);
+ final int idx = rawPattern.indexOf("Is" + capturedGroup);
result = result.replace(idx, idx + 2, "In");
}
}
return result.toString();
}
- public static boolean belongsToTheSameModule(QName targetStmtQName, QName sourceStmtQName) {
+ public static boolean belongsToTheSameModule(final QName targetStmtQName, final QName sourceStmtQName) {
if (targetStmtQName.getModule().equals(sourceStmtQName.getModule())) {
return true;
}
return false;
}
- public static boolean isPresenceContainer(StatementContextBase<?, ?, ?> targetCtx) {
+ public static boolean isPresenceContainer(final StatementContextBase<?, ?, ?> targetCtx) {
if (!targetCtx.getPublicDefinition().equals(Rfc6020Mapping.CONTAINER)) {
return false;
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.stmt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.stmt.test.StmtTestUtils;
+
+public class Bug6180Test {
+
+ @Test
+ public void stringTest() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSources(new File(getClass().getResource(
+ "/bugs/bug6180/string-test.yang").toURI()));
+ assertNotNull(schemaContext);
+ assertEquals(1, schemaContext.getModules().size());
+ final Module module = schemaContext.getModules().iterator().next();
+ assertEquals(" 1. this text contains \"string enclosed in double quotes\" and"+
+ " special characters: \\,\n,\t 2. this text contains \"string enclosed in double quotes\" and"+
+ " special characters: \\,\n,\n, 3. this text contains \"string enclosed in double quotes\" and"+
+ " special characters: \\,\n,\t ", module.getDescription());
+ }
+
+ @Test
+ public void doubleQuotesTest() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSources(new File(getClass().getResource(
+ "/bugs/bug6180/double-quotes.yang").toURI()));
+ assertNotNull(schemaContext);
+ verifyDoubleQuotesExpression(schemaContext);
+ }
+
+ @Test
+ public void doubleQuotesSinbleInsideTest() throws ReactorException, SourceException, FileNotFoundException,
+ URISyntaxException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSources(new File(getClass().getResource(
+ "/bugs/bug6180/double-quotes-single-inside.yang").toURI()));
+ assertNotNull(schemaContext);
+ verifySingleQuotesExpression(schemaContext);
+ }
+
+ @Test
+ public void singleQuotesTest() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSources(new File(getClass().getResource(
+ "/bugs/bug6180/single-quotes.yang").toURI()));
+ assertNotNull(schemaContext);
+ verifyDoubleQuotesExpression(schemaContext);
+ }
+
+ private static void verifyDoubleQuotesExpression(final SchemaContext schemaContext) {
+ final DataSchemaNode dataNodeBar = schemaContext.getDataChildByName(QName.create("foo", "2016-07-11", "bar"));
+ assertTrue(dataNodeBar instanceof ContainerSchemaNode);
+ final ContainerSchemaNode bar = (ContainerSchemaNode) dataNodeBar;
+ final RevisionAwareXPath whenCondition = bar.getConstraints().getWhenCondition();
+ assertEquals("/foo != \"bar\"", whenCondition.toString());
+
+ final Set<TypeDefinition<?>> typeDefinitions = schemaContext.getTypeDefinitions();
+ assertEquals(1, typeDefinitions.size());
+ final TypeDefinition<?> type = typeDefinitions.iterator().next();
+ assertTrue(type instanceof StringTypeDefinition);
+ final List<PatternConstraint> patternConstraints = ((StringTypeDefinition) type).getPatternConstraints();
+ assertEquals(1, patternConstraints.size());
+ final PatternConstraint pattern = patternConstraints.iterator().next();
+ assertEquals("^\".*\"$", pattern.getRegularExpression());
+ assertTrue(Pattern.compile(pattern.getRegularExpression()).matcher("\"enclosed string in quotes\"").matches());
+ }
+
+ private static void verifySingleQuotesExpression(final SchemaContext schemaContext) {
+ final DataSchemaNode dataNodeBar = schemaContext.getDataChildByName(QName.create("foo", "2016-07-11", "bar"));
+ assertTrue(dataNodeBar instanceof ContainerSchemaNode);
+ final ContainerSchemaNode bar = (ContainerSchemaNode) dataNodeBar;
+ final RevisionAwareXPath whenCondition = bar.getConstraints().getWhenCondition();
+ assertEquals("/foo != 'bar'", whenCondition.toString());
+
+ final Set<TypeDefinition<?>> typeDefinitions = schemaContext.getTypeDefinitions();
+ assertEquals(1, typeDefinitions.size());
+ final TypeDefinition<?> type = typeDefinitions.iterator().next();
+ assertTrue(type instanceof StringTypeDefinition);
+ final List<PatternConstraint> patternConstraints = ((StringTypeDefinition) type).getPatternConstraints();
+ assertEquals(1, patternConstraints.size());
+ final PatternConstraint pattern = patternConstraints.iterator().next();
+ assertEquals("^'.*'$", pattern.getRegularExpression());
+ assertTrue(Pattern.compile(pattern.getRegularExpression()).matcher("'enclosed string in quotes'").matches());
+ }
+}
\ No newline at end of file