private Part parsePart(AsciiBuffer value) { if (value.equals(any_child_wildcard)) { return ANY_CHILD; } else if (value.equals(any_descendant_wildcard)) { return ANY_DESCENDANT; } else { if (part_pattern == null || part_pattern.matcher(value.toString()).matches()) { return new LiteralPart(value); } else { throw new PathException( String.format( "Invalid destination path part: '%s', it does not match regex: %s", value, part_pattern)); } } }
/** * Holds the delimiters used to parse paths. * * @author <a href="http://hiramchirino.com">Hiram Chirino</a> */ public class PathParser { public static class PathException extends RuntimeException { public PathException(String message) { super(message); } } public static final PathParser DEFAULT = new PathParser(); public AsciiBuffer any_descendant_wildcard = new AsciiBuffer("**"); public AsciiBuffer any_child_wildcard = new AsciiBuffer("*"); public AsciiBuffer path_seperator = new AsciiBuffer("."); public Pattern part_pattern = Pattern.compile("[a-zA-Z0-9\\_\\-\\%\\~]+"); public Path parsePath(AsciiBuffer subject) { ArrayList<Part> list = new ArrayList<Part>(10); int previous = 0; int lastIndex = subject.getLength() - 1; while (true) { int idx = subject.indexOf(path_seperator, previous); if (idx < 0) { AsciiBuffer buffer = subject.slice(previous, lastIndex + 1).ascii(); list.add(parsePart(buffer)); break; } AsciiBuffer buffer = subject.slice(previous, idx).ascii(); list.add(parsePart(buffer)); previous = idx + 1; } return new Path(new ArrayList(list)); } private Part parsePart(AsciiBuffer value) { if (value.equals(any_child_wildcard)) { return ANY_CHILD; } else if (value.equals(any_descendant_wildcard)) { return ANY_DESCENDANT; } else { if (part_pattern == null || part_pattern.matcher(value.toString()).matches()) { return new LiteralPart(value); } else { throw new PathException( String.format( "Invalid destination path part: '%s', it does not match regex: %s", value, part_pattern)); } } } /** * Converts the path back to the string representation. * * @return */ public String toString(Path path) { StringBuffer buffer = new StringBuffer(); boolean first = true; for (Part p : path.parts) { if (!first) { buffer.append(path_seperator); } buffer.append(p.toString(this)); first = false; } return buffer.toString(); } public void write(Path path, ByteArrayOutputStream os) throws IOException { boolean first = true; for (Part p : path.parts) { if (!first) { path_seperator.writeTo(os); } new AsciiBuffer(p.toString(this)).writeTo(os); first = false; } } static interface PartFilter { public boolean matches(LinkedList<Part> remaining); } class LitteralPathFilter implements PartFilter { private final PartFilter next; private final LiteralPart path; public LitteralPathFilter(PartFilter next, LiteralPart path) { this.next = next; this.path = path; } public boolean matches(LinkedList<Part> remaining) { if (!remaining.isEmpty()) { Part p = remaining.removeFirst(); if (!path.matches(p)) { return false; } if (next != null) { return next.matches(remaining); } else { return remaining.isEmpty(); } } else { return false; } } } static class AnyChildPathFilter implements PartFilter { private final PartFilter next; public AnyChildPathFilter(PartFilter next) { this.next = next; } public boolean matches(LinkedList<Part> remaining) { if (!remaining.isEmpty()) { Part p = remaining.removeFirst(); if (next != null) { return next.matches(remaining); } else { return remaining.isEmpty(); } } else { return false; } } } static class AnyDecendentPathFilter implements PartFilter { private final PartFilter next; public AnyDecendentPathFilter(PartFilter next) { this.next = next; } public boolean matches(LinkedList<Part> remaining) { if (!remaining.isEmpty()) { remaining.clear(); return true; } else { return false; } } } public PathFilter parseFilter(AsciiBuffer path) { ArrayList<Part> parts = new ArrayList<Part>(parsePath(path).parts); Collections.reverse(parts); PartFilter last = null; for (Part p : parts) { if (p.isLiteral()) { last = new LitteralPathFilter(last, (LiteralPart) p); } else if (p == ANY_CHILD) { last = new AnyChildPathFilter(last); } else if (p == ANY_DESCENDANT) { last = new AnyDecendentPathFilter(last); } } final PartFilter filter = last; return new PathFilter() { public boolean matches(Path path) { return filter.matches(new LinkedList(path.parts)); } }; } public static boolean containsWildCards(Path path) { for (Part p : path.parts) { if (p == ANY_DESCENDANT || p == ANY_CHILD) { return true; } } return false; } }