You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2008/07/08 16:37:23 UTC
svn commit: r674843 - in /jackrabbit/trunk/jackrabbit-spi-commons/src:
main/java/org/apache/jackrabbit/spi/commons/name/
test/java/org/apache/jackrabbit/spi/commons/name/
Author: tripod
Date: Tue Jul 8 07:37:23 2008
New Revision: 674843
URL: http://svn.apache.org/viewvc?rev=674843&view=rev
Log:
JCR-1662 Add pattern matching for paths
Added:
jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java (with props)
jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java (with props)
jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java (with props)
jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java (with props)
jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java (with props)
Modified:
jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/TestAll.java
Added: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java?rev=674843&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java (added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java Tue Jul 8 07:37:23 2008
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.spi.commons.name;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * A MatchResult instance represents the result of matching a {@link Pattern} against
+ * a {@link Path}.
+ */
+public class MatchResult {
+ private final Path path;
+ private final int pathLength;
+ private int matchPos;
+ private final int matchLength;
+
+ MatchResult(Path path, int length) {
+ this(path, 0, length);
+ }
+
+ MatchResult(Path path, int pos, int length) {
+ super();
+ if (!path.isNormalized()) {
+ throw new IllegalArgumentException("Path not normalized");
+ }
+ this.path = path;
+ this.matchPos = pos;
+ this.matchLength = length;
+ this.pathLength = path.getLength();
+ }
+
+ /**
+ * Returns the remaining path after the matching part.
+ * @return The remaining path after the matching part such that the path constructed from
+ * {@link #getMatch()} followed by {@link #getRemainder()} is the original path or
+ * <code>null</code> if {@link #isFullMatch()} is <code>true</code>.
+ */
+ public Path getRemainder() {
+ if (matchPos + matchLength >= pathLength) {
+ return null;
+ }
+ else {
+ try {
+ return path.subPath(matchPos + matchLength, pathLength);
+ }
+ catch (RepositoryException e) {
+ throw (IllegalStateException) new IllegalStateException("Path not normalized")
+ .initCause(e);
+ }
+ }
+ }
+
+ /**
+ * Returns the path which was matched by the {@link Pattern}.
+ * @return The path which was matched such that the path constructed from
+ * {@link #getMatch()} followed by {@link #getRemainder()} is the original path or
+ * <code>null</code> if {@link #getMatchLength()} is <code>0</code>.
+ */
+ public Path getMatch() {
+ if (matchLength == 0) {
+ return null;
+ }
+ else {
+ try {
+ return path.subPath(matchPos, matchPos + matchLength);
+ }
+ catch (RepositoryException e) {
+ throw (IllegalStateException) new IllegalStateException("Path not normalized")
+ .initCause(e);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the position of the match
+ * @return
+ */
+ public int getMatchPos() {
+ return matchPos;
+ }
+
+ /**
+ * Returns the number of elements which where matched by the {@link Pattern}.
+ * @return
+ */
+ public int getMatchLength() {
+ return matchLength;
+ }
+
+ /**
+ * Returns true if the {@link Pattern} matched anything or false otherwise.
+ * @return
+ */
+ public boolean isMatch() {
+ return matchLength > 0;
+ }
+
+ /**
+ * Returns true if the {@link Pattern} matched the whole {@link Path}.
+ * @return
+ */
+ public boolean isFullMatch() {
+ return pathLength == matchLength;
+ }
+
+ MatchResult setPos(int matchPos) {
+ this.matchPos = matchPos;
+ return this;
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/MatchResult.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Added: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java?rev=674843&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java (added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java Tue Jul 8 07:37:23 2008
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.spi.commons.name;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * Utility class for matching {@link Pattern}s against {@link Path}es.
+ */
+public final class Matcher {
+
+ private Matcher() {
+ // Don't instantiate
+ }
+
+ /**
+ * Match a pattern against an input path and return the remaining path.
+ * @param pattern
+ * @param input
+ * @return The remaining path after the match or <code>null</code> if the whole path
+ * was matched.
+ * @see MatchResult#getRemainder()
+ */
+ public static Path match(Pattern pattern, Path input) {
+ return pattern.match(input).getRemainder();
+ }
+
+ /**
+ * Checks whether a pattern matches an input path.
+ * @param pattern
+ * @param input
+ * @return <code>true</code> if <code>pattern</code> matches the whole <code>input</code>.
+ * @see MatchResult#isFullMatch()
+ */
+ public static boolean matches(Pattern pattern, Path input) {
+ return pattern.match(input).isFullMatch();
+ }
+
+ /**
+ * Find the first match of a pattern in a path.
+ * @param pattern
+ * @param input
+ * @return A {@link MatchResult} or null if the pattern does not occur in the
+ * input.
+ * @throws IllegalArgumentException if <code>input</code> is not normalized.
+ */
+ public static MatchResult findMatch(Pattern pattern, Path input) {
+ return findMatch(pattern, input, 0);
+ }
+
+ /**
+ * Find the first match of a pattern in a path starting at a given position.
+ * @param pattern
+ * @param input
+ * @param pos
+ * @return A {@link MatchResult} or null if the pattern does not occur in the
+ * input.
+ * @throws IllegalArgumentException if <code>input</code> is not normalized.
+ */
+ public static MatchResult findMatch(Pattern pattern, Path input, int pos) {
+ int length = input.getLength();
+ if (pos < 0 || pos >= length) {
+ throw new IllegalArgumentException("Index out of bounds");
+ }
+
+ try {
+ for (int k = pos; k < length; k++) {
+ Path path = input.subPath(k, length);
+ MatchResult result = pattern.match(path);
+ if (result.isMatch()) {
+ return new MatchResult(input, k, result.getMatchLength());
+ }
+ }
+ return null;
+ }
+ catch (RepositoryException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException("Path not normalizable")
+ .initCause(e);
+ }
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Matcher.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Added: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java?rev=674843&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java (added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java Tue Jul 8 07:37:23 2008
@@ -0,0 +1,505 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.spi.commons.name;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.Path.Element;
+
+/**
+ * Pattern to match normalized {@link Path}s.
+ * A pattern matches either a constant path, a name of a path element, a selection of
+ * either of two patterns or a sequence of two patterns. The matching process is greedy.
+ * That is, whenever a match is not unique only the longest match is considered.
+ * Matching consumes as many elements from the beginning of an input path as possible and
+ * returns what's left as an instance of {@link MatchResult}.
+ * Use the {@link Matcher} class for matching a whole path or finding matches inside a path.
+ */
+public abstract class Pattern {
+
+ /**
+ * Matches this pattern against the input.
+ * @param input path to match with this pattern
+ * @return result from the matching <code>pattern</code> against <code>input</code>
+ * @throws IllegalArgumentException if <code>input</code> is not normalized
+ */
+ public MatchResult match(Path input) {
+ try {
+ return match(new Context(input)).getMatchResult();
+ }
+ catch (RepositoryException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException("Path not normalized")
+ .initCause(e);
+ }
+ }
+
+ protected abstract Context match(Context input) throws RepositoryException;
+
+ /**
+ * Construct a new pattern which matches an exact path
+ * @param path
+ * @return A pattern which matches <code>path</code> and nothing else
+ * @throws IllegalArgumentException if <code>path</code> is <code>null</code>
+ */
+ public static Pattern path(Path path) {
+ if (path == null) {
+ throw new IllegalArgumentException("path cannot be null");
+ }
+ return new PathPattern(path);
+ }
+
+ /**
+ * Construct a new pattern which matches a path element of a given name
+ * @param name
+ * @return A pattern which matches a path element with name <code>name</code>
+ * @throws IllegalArgumentException if <code>name</code> is <code>null</code>
+ */
+ public static Pattern name(Name name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ return new NamePattern(name);
+ }
+
+ /**
+ * Constructs a pattern which matches a path elements against regular expressions.
+ * @param namespaceUri A regular expression used for matching the name space URI of
+ * a path element.
+ * @param localName A regular expression used for matching the local name of a path
+ * element
+ * @return A pattern which matches a path element if namespaceUri matches the
+ * name space URI of the path element and localName matches the local name of the
+ * path element.
+ * @throws IllegalArgumentException if either <code>namespaceUri</code> or
+ * <code>localName</code> is <code>null</code>
+ *
+ * @see java.util.regex.Pattern
+ */
+ public static Pattern name(String namespaceUri, String localName) {
+ if (namespaceUri == null || localName == null) {
+ throw new IllegalArgumentException("neither namespaceUri nor localName can be null");
+ }
+ return new RegexPattern(namespaceUri, localName);
+ }
+
+ private static final Pattern ALL_PATTERN = new Pattern() {
+ protected Context match(Context input) {
+ return input.matchToEnd();
+ }
+
+ public String toString() {
+ return "[ALL]";
+ }
+
+ };
+
+ /**
+ * A pattern which matches all input.
+ * @return
+ */
+ public static Pattern all() {
+ return ALL_PATTERN;
+ }
+
+ private static final Pattern NOTHING_PATTERN = new Pattern() {
+ protected Context match(Context input) {
+ return input.match(0);
+ }
+
+ public String toString() {
+ return "[NOTHING]";
+ }
+ };
+
+ /**
+ * A pattern which matches nothing.
+ * @return
+ */
+ public static Pattern nothing() {
+ return NOTHING_PATTERN;
+ }
+
+ /**
+ * A pattern which matches <code>pattern1</code> followed by <code>pattern2</code> and
+ * returns the longer of the two matches.
+ * @param pattern1
+ * @param pattern2
+ * @return
+ * @throws IllegalArgumentException if either argument is <code>null</code>
+ */
+ public static Pattern selection(Pattern pattern1, Pattern pattern2) {
+ if (pattern1 == null || pattern2 == null) {
+ throw new IllegalArgumentException("Neither pattern can be null");
+ }
+ return new SelectPattern(pattern1, pattern2);
+ }
+
+ /**
+ * A pattern which matches <code>pattern1</code> followed by <code>pattern2</code>.
+ * @param pattern1
+ * @param pattern2
+ * @return
+ */
+ public static Pattern sequence(Pattern pattern1, Pattern pattern2) {
+ if (pattern1 == null || pattern2 == null) {
+ throw new IllegalArgumentException("Neither pattern can be null");
+ }
+ return new SequencePattern(pattern1, pattern2);
+ }
+
+ /**
+ * A pattern which matches <code>pattern</code> as many times as possible
+ * @param pattern
+ * @return
+ */
+ public static Pattern repeat(Pattern pattern) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern can not be null");
+ }
+ return new RepeatPattern(pattern);
+ }
+
+ /**
+ * A pattern which matches <code>pattern</code> as many times as possible
+ * but at least <code>min</code> times and at most <code>max</code> times.
+ * @param pattern
+ * @param min
+ * @param max
+ * @return
+ */
+ public static Pattern repeat(Pattern pattern, int min, int max) {
+ if (pattern == null) {
+ throw new IllegalArgumentException("Pattern can not be null");
+ }
+ return new RepeatPattern(pattern, min, max);
+ }
+
+ // -----------------------------------------------------< Context >---
+
+ private static class Context {
+ private final Path path;
+ private final int length;
+ private final int pos;
+ private final boolean isMatch;
+
+ public Context(Path path) {
+ super();
+ this.path = path;
+ length = path.getLength();
+ isMatch = false;
+ pos = 0;
+ }
+
+ public Context(Context context, int pos, boolean matched) {
+ path = context.path;
+ length = context.length;
+ this.pos = pos;
+ this.isMatch = matched;
+ if (pos > length) {
+ throw new IllegalArgumentException("Cannot match beyond end of input");
+ }
+ }
+
+ public Context matchToEnd() {
+ return new Context(this, length, true);
+ }
+
+ public Context match(int count) {
+ return new Context(this, pos + count, true);
+ }
+
+ public Context noMatch() {
+ return new Context(this, this.pos, false);
+ }
+
+ public boolean isMatch() {
+ return isMatch;
+ }
+
+ public Path getRemainder() throws RepositoryException {
+ if (pos >= length) {
+ return null;
+ }
+ else {
+ return path.subPath(pos, length);
+ }
+ }
+
+ public boolean isExhausted() {
+ return pos == length;
+ }
+
+ public MatchResult getMatchResult() {
+ return new MatchResult(path, isMatch? pos : 0);
+ }
+
+ public String toString() {
+ return pos + " @ " + path;
+ }
+
+ }
+
+ // -----------------------------------------------------< SelectPattern >---
+
+ private static class SelectPattern extends Pattern {
+ private final Pattern pattern1;
+ private final Pattern pattern2;
+
+ public SelectPattern(Pattern pattern1, Pattern pattern2) {
+ super();
+ this.pattern1 = pattern1;
+ this.pattern2 = pattern2;
+ }
+
+ protected Context match(Context input) throws RepositoryException {
+ Context remainder1 = pattern1.match(input);
+ Context remainder2 = pattern2.match(input);
+ return remainder1.pos > remainder2.pos ?
+ remainder1 : remainder2;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("(")
+ .append(pattern1)
+ .append("|")
+ .append(pattern2)
+ .append(")")
+ .toString();
+ }
+ }
+
+ // -----------------------------------------------------< SequencePattern >---
+
+ private static class SequencePattern extends Pattern {
+ private final Pattern pattern1;
+ private final Pattern pattern2;
+
+ public SequencePattern(Pattern pattern1, Pattern pattern2) {
+ super();
+ this.pattern1 = pattern1;
+ this.pattern2 = pattern2;
+ }
+
+ protected Context match(Context input) throws RepositoryException {
+ Context context1 = pattern1.match(input);
+ if (context1.isMatch()) {
+ return pattern2.match(context1);
+ }
+ else {
+ return input.noMatch();
+ }
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("(")
+ .append(pattern1)
+ .append(", ")
+ .append(pattern2)
+ .append(")")
+ .toString();
+ }
+ }
+
+ // -----------------------------------------------------< RepeatPattern >---
+
+ private static class RepeatPattern extends Pattern {
+ private final Pattern pattern;
+ private final int min;
+ private final int max;
+ private boolean hasBounds;
+
+ public RepeatPattern(Pattern pattern) {
+ this(pattern, 0, 0);
+ this.hasBounds = false;
+ }
+
+ public RepeatPattern(Pattern pattern, int min, int max) {
+ super();
+ this.pattern = pattern;
+ this.min = min;
+ this.max = max;
+ this.hasBounds = true;
+ }
+
+ protected Context match(Context input) throws RepositoryException {
+ Context nextInput;
+ Context output = input.match(0);
+ int matchCount = -1;
+ do {
+ nextInput = output;
+ output = pattern.match(nextInput);
+ matchCount++;
+ } while (output.isMatch() && (output.pos > nextInput.pos));
+
+ if (!hasBounds() || (min <= matchCount && matchCount <= max)) {
+ return nextInput;
+ }
+ else {
+ return input.noMatch();
+ }
+ }
+
+ private boolean hasBounds() {
+ return hasBounds;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("(")
+ .append(pattern)
+ .append(")*")
+ .toString();
+ }
+
+ }
+
+ // -----------------------------------------------------< PathPattern >---
+
+ private static class PathPattern extends Pattern {
+ private final Path path;
+ private final Element[] patternElements;
+
+ public PathPattern(Path path) {
+ super();
+ this.path = path;
+ patternElements = path.getElements();
+ }
+
+ protected Context match(Context input) throws RepositoryException {
+ if (input.isExhausted()) {
+ return input;
+ }
+
+ Path inputPath = input.getRemainder();
+ if (!inputPath.isNormalized()) {
+ throw new IllegalArgumentException("Not normalized");
+ }
+
+ Element[] inputElements = inputPath.getElements();
+ int inputLength = inputElements.length;
+ int patternLength = patternElements.length;
+ if (patternLength > inputLength) {
+ return input.noMatch();
+ }
+
+ for (int k = 0; k < patternLength; k++) {
+ if (!patternElements[k].equals(inputElements[k])) {
+ return input.noMatch();
+ }
+ }
+
+ return input.match(patternLength);
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("\"")
+ .append(path)
+ .append("\"")
+ .toString();
+ }
+ }
+
+ // -----------------------------------------------------< AbstractNamePattern >---
+
+ private static abstract class AbstractNamePattern extends Pattern {
+ protected abstract boolean matches(Element element);
+
+ protected Context match(Context input) throws RepositoryException {
+ if (input.isExhausted()) {
+ return input.noMatch();
+ }
+
+ Path inputPath = input.getRemainder();
+ if (!inputPath.isNormalized()) {
+ throw new IllegalArgumentException("Not normalized");
+ }
+
+ Element[] inputElements = inputPath.getElements();
+ if (inputElements.length < 1 || !matches(inputElements[0])) {
+ return input.noMatch();
+ }
+
+ return input.match(1);
+ }
+
+ }
+
+ // -----------------------------------------------------< NameNamePattern >---
+
+ private static class NamePattern extends AbstractNamePattern {
+ private final Name name;
+
+ public NamePattern(Name name) {
+ super();
+ this.name = name;
+ }
+
+ protected boolean matches(Element element) {
+ return name.equals(element.getName());
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("\"")
+ .append(name)
+ .append("\"")
+ .toString();
+ }
+ }
+
+ // -----------------------------------------------------< StringNamePattern >---
+
+ private static class RegexPattern extends AbstractNamePattern {
+ private final java.util.regex.Pattern namespaceUri;
+ private final java.util.regex.Pattern localName;
+ private final String localNameStr;
+ private final String namespaceUriStr;
+
+ public RegexPattern(String namespaceUri, String localName) {
+ super();
+
+ this.namespaceUri = java.util.regex.Pattern.compile(namespaceUri);
+ this.localName = java.util.regex.Pattern.compile(localName);
+ this.namespaceUriStr = namespaceUri;
+ this.localNameStr = localName;
+ }
+
+ protected boolean matches(Element element) {
+ Name name = element.getName();
+ boolean nsMatches = namespaceUri.matcher(name.getNamespaceURI()).matches();
+ boolean localMatches = localName.matcher(name.getLocalName()).matches();
+ return nsMatches && localMatches;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("\"{")
+ .append(namespaceUriStr)
+ .append("}")
+ .append(localNameStr)
+ .append("\"")
+ .toString();
+ }
+ }
+
+}
+
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/name/Pattern.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Added: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java?rev=674843&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java (added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java Tue Jul 8 07:37:23 2008
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.spi.commons.name;
+
+import javax.jcr.RepositoryException;
+
+import junit.framework.TestCase;
+
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+
+public class MatcherTest extends TestCase {
+ private final static PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();
+ private final static Path PATH1 = PATH_FACTORY.create("{}\t{}a\t{}b\t{}c\t{}d\t{}e\t{}f\t{}g\t{}h\t{}i\t{}j\t{}k");
+ private static final Path PATH2 = PATH_FACTORY.create("{}a\t{}a\t{}a\t{}a\t{}a\t{}b");
+
+ public void testFindMatch() throws RepositoryException {
+ int k = 1;
+ for (char c = 'a'; c <= 'k'; c++) {
+ Pattern pattern = Pattern.name("", Character.toString(c));
+ MatchResult result = Matcher.findMatch(pattern, PATH1);
+ assertEquals("Match @ " + k, k, result.getMatchPos());
+ assertEquals("Match @ " + k, PATH1.subPath(k, k + 1), result.getMatch());
+ assertEquals("Match @ " + k, c == 'k'? null : PATH1.subPath(k + 1, PATH1.getLength()), result.getRemainder());
+ assertEquals("MatchLength == 1", 1, result.getMatchLength());
+ k++;
+ }
+ }
+
+ public void testFindMatchPos() throws RepositoryException {
+ Pattern pattern = Pattern.name("", ".");
+ int k = 1;
+ for (MatchResult result = Matcher.findMatch(pattern, PATH1);
+ result.getMatchPos() + 1 < PATH1.getLength();
+ result = Matcher.findMatch(pattern, PATH1, result.getMatchPos() + 1)) {
+
+ assertEquals("Match @ " + k, k, result.getMatchPos());
+ assertEquals("Match @ " + k, PATH1.subPath(k, k + 1), result.getMatch());
+ assertEquals("Match @ " + k, PATH1.subPath(k + 1, PATH1.getLength()), result.getRemainder());
+ assertEquals("MatchLength == 1", 1, result.getMatchLength());
+ k++;
+ }
+
+ pattern = Pattern.name("", "any");
+ assertEquals(pattern + " does not match " + PATH1, null, Matcher.findMatch(pattern, PATH1));
+ }
+
+ public void testGreedyRepeat() {
+ Pattern pattern = Pattern.sequence(
+ Pattern.repeat(
+ Pattern.sequence(
+ Pattern.name("", ".*"),
+ Pattern.name("", "a"))),
+ Pattern.name("", "b"));
+
+ assertEquals(pattern + " matches " + PATH2 + " @1", 1, Matcher.findMatch(pattern, PATH2).getMatchPos());
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/MatcherTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Added: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java?rev=674843&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java (added)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java Tue Jul 8 07:37:23 2008
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.spi.commons.name;
+
+import javax.jcr.RepositoryException;
+
+import junit.framework.TestCase;
+
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.Path.Element;
+
+public class PatternTest extends TestCase {
+ private static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();
+ private static final NameFactory NAME_FACTORY = NameFactoryImpl.getInstance();
+
+ private static final Path PATH1 = PATH_FACTORY.create("{}\t{}www\t{}day\t{}com\t{}jcr\t{}1\t{}0");
+ private static final Path PATH2 = PATH_FACTORY.create("{}\t{}jackrabbit\t{}apache\t{}org");
+ private static final Path PATH3 = PATH_FACTORY.create("{}a\t{}a\t{}a\t{}a\t{}a\t{}b");
+
+ public void testPathPattern() throws RepositoryException {
+ int len = PATH1.getLength();
+ for (int k = 1; k < len; k++) {
+ Pattern pattern = Pattern.path(PATH1.subPath(0, len - k));
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertEquals(errMsg(pattern, PATH1), PATH1.subPath(0, len - k), result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), PATH1.subPath(len - k, len), result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), PATH1.subPath(len - k, len), Matcher.match(pattern, PATH1));
+ }
+
+ Pattern pattern = Pattern.path(PATH1);
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+
+ public void testNamePattern() throws RepositoryException {
+ Element[] elements = PATH1.getElements();
+ Path path = PATH1;
+ for (int k = 0; k < elements.length; k++) {
+ Pattern pattern = Pattern.name(elements[k].getName());
+ MatchResult result = pattern.match(path);
+ Path remainder = result.getRemainder();
+ assertTrue(errMsg(pattern, path), result.isMatch());
+ assertEquals(errMsg(pattern, path), path.subPath(0, 1), result.getMatch());
+ if (k + 1 == elements.length) {
+ assertTrue(errMsg(pattern, path), result.isFullMatch());
+ assertTrue(errMsg(pattern, path), Matcher.matches(pattern, path));
+ assertEquals(errMsg(pattern, path), null, remainder);
+ assertEquals(errMsg(pattern, path), null, Matcher.match(pattern, path));
+ }
+ else {
+ assertEquals(errMsg(pattern, path), path.subPath(1, path.getLength()), remainder);
+ assertEquals(errMsg(pattern, path), path.subPath(1, path.getLength()), Matcher.match(pattern, path));
+ }
+ path = remainder;
+ }
+ }
+
+ public void testRegexPattern() {
+ Path path = PATH_FACTORY.create("{}goodday");
+ Pattern pattern = Pattern.name(".*", "go*d+ay");
+ MatchResult result = pattern.match(path);
+ assertTrue(errMsg(pattern, path), result.isMatch());
+ assertTrue(errMsg(pattern, path), result.isFullMatch());
+ assertTrue(errMsg(pattern, path), Matcher.matches(pattern, path));
+ assertEquals(errMsg(pattern, path), path, result.getMatch());
+ assertEquals(errMsg(pattern, path), null, result.getRemainder());
+ assertEquals(errMsg(pattern, path), null, Matcher.match(pattern, path));
+
+ pattern = Pattern.name("", "goodday");
+ result = pattern.match(path);
+ assertTrue(errMsg(pattern, path), result.isMatch());
+ assertTrue(errMsg(pattern, path), result.isFullMatch());
+ assertTrue(errMsg(pattern, path), Matcher.matches(pattern, path));
+ assertEquals(errMsg(pattern, path), path, result.getMatch());
+ assertEquals(errMsg(pattern, path), null, result.getRemainder());
+ assertEquals(errMsg(pattern, path), null, Matcher.match(pattern, path));
+ }
+
+ public void testAllPattern() {
+ Pattern pattern = Pattern.all();
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+
+ public void testNothingPattern() {
+ Pattern pattern = Pattern.nothing();
+ MatchResult result = pattern.match(PATH1);
+ assertFalse(errMsg(pattern, PATH1), result.isMatch());
+ assertFalse(errMsg(pattern, PATH1), result.isFullMatch());
+ assertFalse(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), null, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), PATH1, Matcher.match(pattern, PATH1));
+ }
+
+ public void testSelectPattern() {
+ Pattern pattern = Pattern.selection(
+ Pattern.path(PATH2),
+ Pattern.path(PATH1));
+
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+
+ public void testOptionalPattern() {
+ Pattern pattern = Pattern.selection(
+ Pattern.nothing(),
+ Pattern.path(PATH1));
+
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+
+ public void testGreedySelection() {
+ Path path = PATH_FACTORY.create("{}a\t{}a\t{}a\t{}a\t{}a");
+ Path expectedMatch = PATH_FACTORY.create("{}a\t{}a\t{}a");
+ Path expectedRemainder = PATH_FACTORY.create("{}a\t{}a");
+ Pattern pattern1 = Pattern.path(PATH_FACTORY.create("{}a\t{}a"));
+ Pattern pattern2 = Pattern.path(PATH_FACTORY.create("{}a\t{}a\t{}a"));
+
+ Pattern pattern = Pattern.selection(pattern1, pattern2);
+ MatchResult result = pattern.match(path);
+ assertTrue(errMsg(pattern, path), result.isMatch());
+ assertFalse(errMsg(pattern, path), result.isFullMatch());
+ assertFalse(errMsg(pattern, path), Matcher.matches(pattern, path));
+ assertEquals(errMsg(pattern, path), expectedMatch, result.getMatch());
+ assertEquals(errMsg(pattern, path), expectedRemainder, result.getRemainder());
+ assertEquals(errMsg(pattern, path), expectedRemainder, Matcher.match(pattern, path));
+
+ pattern = Pattern.selection(pattern2, pattern1);
+ result = pattern.match(path);
+ assertTrue(errMsg(pattern, path), result.isMatch());
+ assertFalse(errMsg(pattern, path), result.isFullMatch());
+ assertFalse(errMsg(pattern, path), Matcher.matches(pattern, path));
+ assertEquals(errMsg(pattern, path), expectedMatch, result.getMatch());
+ assertEquals(errMsg(pattern, path), expectedRemainder, result.getRemainder());
+ assertEquals(errMsg(pattern, path), expectedRemainder, Matcher.match(pattern, path));
+ }
+
+
+ public void testSequencePattern() throws RepositoryException {
+ int len = PATH1.getLength();
+ for (int k = 1; k < len; k++) {
+ Pattern pattern = Pattern.sequence(
+ Pattern.path(PATH1.subPath(0, len - k)),
+ Pattern.path(PATH1.subPath(len - k, len)));
+
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+ }
+
+ public void testRepeatPattern() throws RepositoryException {
+ Pattern pattern = Pattern.repeat(
+ Pattern.name(".*", "a"));
+
+ MatchResult result = pattern.match(PATH3);
+ assertTrue(errMsg(pattern, PATH3), result.isMatch());
+ assertEquals(errMsg(pattern, PATH3), 5, result.getMatchLength());
+ assertFalse(errMsg(pattern, PATH3), result.isFullMatch());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(0, 5),result.getMatch());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(5, PATH3.getLength()), result.getRemainder());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(5, PATH3.getLength()), Matcher.match(pattern, PATH3));
+ }
+
+ public void testZeroLengthRepeatPattern() throws RepositoryException {
+ Pattern pattern = Pattern.sequence(
+ Pattern.repeat(
+ Pattern.name("", "any")),
+ Pattern.name("", ".*"));
+
+ MatchResult result = pattern.match(PATH3);
+ assertTrue(errMsg(pattern, PATH3), result.isMatch());
+ assertEquals(errMsg(pattern, PATH3), 1, result.getMatchLength());
+ assertFalse(errMsg(pattern, PATH3), result.isFullMatch());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(0, 1),result.getMatch());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(1, PATH3.getLength()), result.getRemainder());
+ assertEquals(errMsg(pattern, PATH3), PATH3.subPath(1, PATH3.getLength()), Matcher.match(pattern, PATH3));
+ }
+
+ public void testRepeatPatternWithBounds() {
+ for (int i = 0; i <= PATH3.getLength(); i++) {
+ for (int j = 0; j <= PATH3.getLength(); j++) {
+ Pattern pattern = Pattern.repeat(
+ Pattern.name(".*", "a"), i, j);
+
+ MatchResult result = pattern.match(PATH3);
+ if (i <= 5 && 5 <= j) {
+ assertTrue(errMsg(pattern, PATH3), result.isMatch());
+ }
+ else {
+ assertFalse(errMsg(pattern, PATH3), result.isMatch());
+ }
+ }
+ }
+ }
+
+ public void testComplexPattern() {
+ Pattern pattern = Pattern.sequence(
+ Pattern.selection(
+ Pattern.path(PATH2),
+ Pattern.name("", "")),
+ Pattern.selection(
+ Pattern.repeat(Pattern.repeat(Pattern.repeat(
+ Pattern.name(NAME_FACTORY.create("{}www"))))),
+ Pattern.sequence(
+ Pattern.path(PATH_FACTORY.create("{}www\t{}day")),
+ Pattern.all())));
+
+ MatchResult result = pattern.match(PATH1);
+ assertTrue(errMsg(pattern, PATH1), result.isMatch());
+ assertTrue(errMsg(pattern, PATH1), result.isFullMatch());
+ assertTrue(errMsg(pattern, PATH1), Matcher.matches(pattern, PATH1));
+ assertEquals(errMsg(pattern, PATH1), PATH1, result.getMatch());
+ assertEquals(errMsg(pattern, PATH1), null, result.getRemainder());
+ assertEquals(errMsg(pattern, PATH1), null, Matcher.match(pattern, PATH1));
+ }
+
+ // -----------------------------------------------------< private >---
+
+ private static String errMsg(Pattern pattern, Path path) {
+ return pattern + " matches " + path;
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/PatternTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url
Modified: jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/TestAll.java?rev=674843&r1=674842&r2=674843&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-spi-commons/src/test/java/org/apache/jackrabbit/spi/commons/name/TestAll.java Tue Jul 8 07:37:23 2008
@@ -39,6 +39,8 @@
suite.addTestSuite(PathBuilderTest.class);
suite.addTestSuite(PathFactoryTest.class);
suite.addTestSuite(PathTest.class);
+ suite.addTestSuite(PatternTest.class);
+ suite.addTestSuite(MatcherTest.class);
return suite;
}