|
|
@ -50,38 +50,38 @@ public class PathCompiler { |
|
|
|
private static final Cache cache = new Cache(200); |
|
|
|
private static final Cache cache = new Cache(200); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Path compile(String path, Predicate... filters) { |
|
|
|
public static Path compile(final String path, final Predicate... filters) { |
|
|
|
|
|
|
|
|
|
|
|
notEmpty(path, "Path may not be null empty"); |
|
|
|
notEmpty(path, "Path may not be null empty"); |
|
|
|
try { |
|
|
|
try { |
|
|
|
path = path.trim(); |
|
|
|
String trimmedPath = path.trim(); |
|
|
|
|
|
|
|
|
|
|
|
if (path.endsWith("..")) { |
|
|
|
if (trimmedPath.endsWith("..")) { |
|
|
|
throw new InvalidPathException("A path can not end with a scan."); |
|
|
|
throw new InvalidPathException("A path can not end with a scan."); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LinkedList<Predicate> filterList = new LinkedList<Predicate>(asList(filters)); |
|
|
|
LinkedList<Predicate> filterList = new LinkedList<Predicate>(asList(filters)); |
|
|
|
|
|
|
|
|
|
|
|
if (path.charAt(0) != '$' && path.charAt(0) != '@') { |
|
|
|
if (trimmedPath.charAt(0) != '$' && trimmedPath.charAt(0) != '@') { |
|
|
|
path = "$." + path; |
|
|
|
trimmedPath = Utils.concat("$.", trimmedPath); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
boolean isRootPath = (path.charAt(0) == '$'); |
|
|
|
boolean isRootPath = (trimmedPath.charAt(0) == '$'); |
|
|
|
|
|
|
|
|
|
|
|
if (path.charAt(0) == '@') { |
|
|
|
if (trimmedPath.charAt(0) == '@') { |
|
|
|
path = "$" + path.substring(1); |
|
|
|
trimmedPath = Utils.concat("$", trimmedPath.substring(1)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (path.length() > 1 && |
|
|
|
if (trimmedPath.length() > 1 && |
|
|
|
path.charAt(1) != '.' && |
|
|
|
trimmedPath.charAt(1) != '.' && |
|
|
|
path.charAt(1) != '[') { |
|
|
|
trimmedPath.charAt(1) != '[') { |
|
|
|
throw new InvalidPathException("Invalid path " + path); |
|
|
|
throw new InvalidPathException("Invalid path " + trimmedPath); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String cacheKey = path + isRootPath + filterList.toString(); |
|
|
|
String cacheKey = Utils.concat(trimmedPath, Boolean.toString(isRootPath), filterList.toString()); |
|
|
|
Path p = cache.get(cacheKey); |
|
|
|
Path p = cache.get(cacheKey); |
|
|
|
if (p != null) { |
|
|
|
if (p != null) { |
|
|
|
if (logger.isDebugEnabled()) logger.debug("Using cached path: " + cacheKey); |
|
|
|
if (logger.isDebugEnabled()) logger.debug("Using cached path: {}", cacheKey); |
|
|
|
return p; |
|
|
|
return p; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -93,7 +93,7 @@ public class PathCompiler { |
|
|
|
String fragment = ""; |
|
|
|
String fragment = ""; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
do { |
|
|
|
char current = path.charAt(i); |
|
|
|
char current = trimmedPath.charAt(i); |
|
|
|
|
|
|
|
|
|
|
|
switch (current) { |
|
|
|
switch (current) { |
|
|
|
case SPACE: |
|
|
|
case SPACE: |
|
|
@ -103,27 +103,27 @@ public class PathCompiler { |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case BRACKET_OPEN: |
|
|
|
case BRACKET_OPEN: |
|
|
|
positions = fastForwardUntilClosed(path, i); |
|
|
|
positions = fastForwardUntilClosed(trimmedPath, i); |
|
|
|
fragment = path.substring(i, i + positions); |
|
|
|
fragment = trimmedPath.substring(i, i + positions); |
|
|
|
i += positions; |
|
|
|
i += positions; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case PERIOD: |
|
|
|
case PERIOD: |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
if ( i < path.length() && path.charAt(i) == PERIOD) { |
|
|
|
if ( i < trimmedPath.length() && trimmedPath.charAt(i) == PERIOD) { |
|
|
|
//This is a deep scan
|
|
|
|
//This is a deep scan
|
|
|
|
fragment = ".."; |
|
|
|
fragment = ".."; |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
positions = fastForward(path, i); |
|
|
|
positions = fastForward(trimmedPath, i); |
|
|
|
if (positions == 0) { |
|
|
|
if (positions == 0) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
} else if (positions == 1 && path.charAt(i) == '*') { |
|
|
|
} else if (positions == 1 && trimmedPath.charAt(i) == '*') { |
|
|
|
fragment = new String("[*]"); |
|
|
|
fragment = new String("[*]"); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
assertValidFieldChars(path, i, positions); |
|
|
|
assertValidFieldChars(trimmedPath, i, positions); |
|
|
|
|
|
|
|
|
|
|
|
fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; |
|
|
|
fragment = Utils.concat(PROPERTY_OPEN, trimmedPath.substring(i, i + positions), PROPERTY_CLOSE); |
|
|
|
} |
|
|
|
} |
|
|
|
i += positions; |
|
|
|
i += positions; |
|
|
|
} |
|
|
|
} |
|
|
@ -133,9 +133,9 @@ public class PathCompiler { |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
positions = fastForward(path, i); |
|
|
|
positions = fastForward(trimmedPath, i); |
|
|
|
|
|
|
|
|
|
|
|
fragment = PROPERTY_OPEN + path.substring(i, i + positions) + PROPERTY_CLOSE; |
|
|
|
fragment = Utils.concat(PROPERTY_OPEN, trimmedPath.substring(i, i + positions), PROPERTY_CLOSE); |
|
|
|
i += positions; |
|
|
|
i += positions; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -145,7 +145,7 @@ public class PathCompiler { |
|
|
|
root.append(PathComponentAnalyzer.analyze(fragment, filterList)); |
|
|
|
root.append(PathComponentAnalyzer.analyze(fragment, filterList)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} while (i < path.length()); |
|
|
|
} while (i < trimmedPath.length()); |
|
|
|
|
|
|
|
|
|
|
|
Path pa = new CompiledPath(root, isRootPath); |
|
|
|
Path pa = new CompiledPath(root, isRootPath); |
|
|
|
|
|
|
|
|
|
|
|