Updated SchemaNodeIdentifier namespace handling.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / Utils.java
index 7737c5e258ab3a3e5a4d572ae26399e5a08df459..e491c5975db17f0ed7aad8f7f2f411273f3ab349 100644 (file)
@@ -11,6 +11,7 @@ import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.f
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -22,7 +23,9 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.regex.Pattern;
 import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
@@ -67,23 +70,25 @@ public final class Utils {
     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 Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings().trimResults();
+    private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
+    private static final Pattern PATH_ABS = Pattern.compile("/[^/].*");
 
-    private static final char SEPARATOR_NODENAME = '/';
-
-    private static final String REGEX_PATH_ABS = "/[^/].*";
-
-    public static final char SEPARATOR = ' ';
+    // XPathFactory is documented as non-threadsafe
+    @GuardedBy("Utils.class")
+    private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
 
     private Utils() {
+        throw new UnsupportedOperationException();
     }
 
     public static Collection<SchemaNodeIdentifier.Relative> transformKeysStringToKeyNodes(final StmtContext<?, ?, ?> ctx,
             final String value) {
-        Splitter keySplitter = Splitter.on(SEPARATOR).omitEmptyStrings().trimResults();
-        List<String> keyTokens = keySplitter.splitToList(value);
+        List<String> keyTokens = SPACE_SPLITTER.splitToList(value);
 
         // to detect if key contains duplicates
         if ((new HashSet<>(keyTokens)).size() < keyTokens.size()) {
+            // FIXME: report all duplicate keys
             throw new IllegalArgumentException();
         }
 
@@ -100,20 +105,19 @@ public final class Utils {
     }
 
     public static List<String> splitPathToNodeNames(final String path) {
-
-        Splitter keySplitter = Splitter.on(SEPARATOR_NODENAME).omitEmptyStrings().trimResults();
-        return keySplitter.splitToList(path);
+        return SLASH_SPLITTER.splitToList(path);
     }
 
     public static void validateXPath(final StmtContext<?, ?, ?> ctx, final String path) {
-
-        final XPath xPath = XPathFactory.newInstance().newXPath();
+        final XPath xPath;
+        synchronized (Utils.class) {
+            xPath = XPATH_FACTORY.newXPath();
+        }
 
         try {
             xPath.compile(path);
         } catch (XPathExpressionException e) {
-            throw new IllegalArgumentException(String.format("Argument %s is not valid XPath string at %s", path, ctx
-                    .getStatementSourceReference().toString()), e);
+            LOG.warn("Argument {} is not valid XPath string at {}", path, ctx.getStatementSourceReference(), e);
         }
     }
 
@@ -125,7 +129,7 @@ public final class Utils {
 
         validateXPath(ctx, trimSingleLastSlashFromXPath(path));
 
-        return path.matches(REGEX_PATH_ABS);
+        return PATH_ABS.matcher(path).matches();
     }
 
     public static QName trimPrefix(final QName identifier) {
@@ -179,7 +183,7 @@ public final class Utils {
         validateXPath(ctx, trimmedPath);
 
         List<String> nodeNames = splitPathToNodeNames(trimmedPath);
-        List<QName> qNames = new ArrayList<>();
+        List<QName> qNames = new ArrayList<>(nodeNames.size());
 
         for (String nodeName : nodeNames) {
             try {
@@ -217,8 +221,7 @@ public final class Utils {
     }
 
     public static QName qNameFromArgument(StmtContext<?, ?, ?> ctx, final String value) {
-
-        if (value == null || value.equals("")) {
+        if (Strings.isNullOrEmpty(value)) {
             return ctx.getPublicDefinition().getStatementName();
         }
 
@@ -251,10 +254,8 @@ public final class Utils {
             break;
         }
 
-        if (qNameModule == null) {
-            throw new IllegalArgumentException("Error in module '" + ctx.getRoot().rawStatementArgument()
-                    + "': can not resolve QNameModule for '" + value + "'.");
-        }
+        Preconditions.checkArgument(qNameModule != null, "Error in module '%s': can not resolve QNameModule for '%s'.",
+                ctx.getRoot().rawStatementArgument(), value);
 
         QNameModule resultQNameModule = qNameModule.getRevision() == null ? QNameModule.create(
                 qNameModule.getNamespace(), SimpleDateFormatUtil.DEFAULT_DATE_REV) : qNameModule;
@@ -296,52 +297,9 @@ public final class Utils {
     }
 
     @Nullable
-    public static StatementContextBase<?, ?, ?> findNode(final StatementContextBase<?, ?, ?> rootStmtCtx,
-            final Iterable<QName> path) {
-
-        StatementContextBase<?, ?, ?> parent = rootStmtCtx;
-
-        Iterator<QName> pathIter = path.iterator();
-        while (pathIter.hasNext()) {
-            QName nextPathQName = pathIter.next();
-            StatementContextBase<?, ?, ?> foundSubstatement = getSubstatementByQName(parent, nextPathQName);
-
-            if (foundSubstatement == null) {
-                return null;
-            }
-            if (!pathIter.hasNext()) {
-                return foundSubstatement;
-            }
-
-            parent = foundSubstatement;
-        }
-
-        return null;
-    }
-
-    public static StatementContextBase<?, ?, ?> getSubstatementByQName(final StatementContextBase<?, ?, ?> parent,
-            final QName nextPathQName) {
-
-        Collection<StatementContextBase<?, ?, ?>> declaredSubstatement = parent.declaredSubstatements();
-        Collection<StatementContextBase<?, ?, ?>> effectiveSubstatement = parent.effectiveSubstatements();
-
-        Collection<StatementContextBase<?, ?, ?>> allSubstatements = new LinkedList<>();
-        allSubstatements.addAll(declaredSubstatement);
-        allSubstatements.addAll(effectiveSubstatement);
-
-        for (StatementContextBase<?, ?, ?> substatement : allSubstatements) {
-            if (nextPathQName.equals(substatement.getStatementArgument())) {
-                return substatement;
-            }
-        }
-
-        return null;
-    }
-
-    @Nullable
-    public static StatementContextBase<?, ?, ?> findNode(final StatementContextBase<?, ?, ?> rootStmtCtx,
+    public static StatementContextBase<?, ?, ?> findNode(final StmtContext<?, ?, ?> rootStmtCtx,
             final SchemaNodeIdentifier node) {
-        return findNode(rootStmtCtx, node.getPathFromRoot());
+        return (StatementContextBase<?, ?, ?>) rootStmtCtx.getFromNamespace(SchemaNodeIdentifierBuildNamespace.class, node);
     }
 
     public static SchemaPath getSchemaPath(final StmtContext<?, ?, ?> ctx) {
@@ -371,6 +329,7 @@ public final class Utils {
                 }
                 qNamesFromRoot.add(qname);
             } else if (nextStmtArgument instanceof String) {
+                // FIXME: This may yield illegal argument exceptions
                 StatementContextBase<?, ?, ?> originalCtx = ctx
                         .getOriginalCtx();
                 final QName qName = (originalCtx != null) ? qNameFromArgument(