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;
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;
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();
}
}
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);
}
}
validateXPath(ctx, trimSingleLastSlashFromXPath(path));
- return path.matches(REGEX_PATH_ABS);
+ return PATH_ABS.matcher(path).matches();
}
public static QName trimPrefix(final QName identifier) {
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 {
}
public static QName qNameFromArgument(StmtContext<?, ?, ?> ctx, final String value) {
-
- if (value == null || value.equals("")) {
+ if (Strings.isNullOrEmpty(value)) {
return ctx.getPublicDefinition().getStatementName();
}
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;
}
@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) {
}
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(