You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by st...@apache.org on 2012/05/24 14:28:32 UTC
svn commit: r1342226 - in /jackrabbit/oak/trunk/oak-mk: ./
src/main/java/org/apache/jackrabbit/mk/api/
src/main/java/org/apache/jackrabbit/mk/core/
src/main/java/org/apache/jackrabbit/mk/util/
src/test/java/org/apache/jackrabbit/mk/util/
Author: stefan
Date: Thu May 24 12:28:32 2012
New Revision: 1342226
URL: http://svn.apache.org/viewvc?rev=1342226&view=rev
Log:
OAK-75: specify format and semantics of 'filter' parameter in MicroKernel API:
NameFilter optimization
javadoc for :hash and :childNodeCount metadata
Modified:
jackrabbit/oak/trunk/oak-mk/pom.xml
jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java
jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java
jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java
Modified: jackrabbit/oak/trunk/oak-mk/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/pom.xml?rev=1342226&r1=1342225&r2=1342226&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-mk/pom.xml Thu May 24 12:28:32 2012
@@ -28,7 +28,7 @@
</parent>
<artifactId>oak-mk</artifactId>
- <name>Oak Microkernel</name>
+ <name>Oak MicroKernel</name>
<packaging>bundle</packaging>
<build>
@@ -95,7 +95,6 @@
<scope>provided</scope>
</dependency>
-
<!-- commons dependency -->
<dependency>
<groupId>org.apache.jackrabbit</groupId>
Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java?rev=1342226&r1=1342225&r2=1342226&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java Thu May 24 12:28:32 2012
@@ -43,11 +43,14 @@ import java.io.InputStream;
* <li>supported property types: string, number, boolean, array</li>
* <li>a property value is stored and used as an opaque, unparsed character sequence</li>
* </ul>
+ * TODO specify retention policy for old revisions (i.e. minimal guaranteed retention period)
*/
public interface MicroKernel {
/**
* Dispose this instance.
+ *
+ * TODO remove lifecycle method from MicroKernel API (OAK-32)
*/
void dispose();
@@ -212,16 +215,16 @@ public interface MicroKernel {
* {@code :childNodeCount}). Example:
* <pre>
* {
- * "someprop": "someval",
- * ":childNodeCount": 2,
- * "child1" : {
- * "prop1": "foo",
- * ":childNodeCount": 2
- * },
- * "child2": {
- * "prop1": "bar"
- * ":childNodeCount": 0
- * }
+ * "someprop" : "someval",
+ * ":childNodeCount" : 2,
+ * "child1" : {
+ * "prop1" : 123,
+ * ":childNodeCount" : 2
+ * },
+ * "child2" : {
+ * "prop1" : "bar",
+ * ":childNodeCount" : 0
+ * }
* }
* </pre>
* Remarks:
@@ -240,6 +243,7 @@ public interface MicroKernel {
* @param revisionId revision id, if {@code null} the current head revision is assumed
* @return node tree in JSON format or {@code null} if the specified node does not exist
* @throws MicroKernelException if the specified revision does not exist or if another error occurs
+ * @see #getNodes(String, String, int, long, int, String)
*/
String /* jsonTree */ getNodes(String path, String revisionId) throws MicroKernelException;
@@ -264,11 +268,35 @@ public interface MicroKernel {
* </tr>
* </table>
* <p/>
+ * Example (depth=1):
+ * <pre>
+ * {
+ * "someprop" : "someval",
+ * ":childNodeCount" : 2,
+ * "child1" : {
+ * "prop1" : 123,
+ * ":childNodeCount" : 2
+ * },
+ * "child2" : {
+ * "prop1" : "bar",
+ * ":childNodeCount" : 0
+ * }
+ * }
+ * </pre>
+ * Remarks:
+ * <ul>
+ * <li>If the property {@code :childNodeCount} equals 0, then the
+ * node does not have any child nodes.
+ * <li>If the value of {@code :childNodeCount} is larger than the number
+ * of returned child nodes, then the node has more child nodes than those
+ * included in the tree. Large number of child nodes can be retrieved in
+ * chunks using {@link #getNodes(String, String, int, long, int, String)}</li>
+ * </ul>
* The {@code offset} and {@code count} parameters are only applied to the
* direct child nodes of the root of the returned node tree.
* <p/>
* The optional {@code filter} parameter allows to specify glob patterns for names of
- * nodes and properties to be included or excluded.
+ * nodes and/or properties to be included or excluded.
* <p/>
* Example:
* <pre>
@@ -278,8 +306,8 @@ public interface MicroKernel {
* }
* </pre>
* In the above example all child nodes with names starting with "foo" will
- * included, except for nodes named "foo1"; similarly, all properties will
- * be included except for the ":childNodeCount" meta data property.
+ * be included, except for nodes named "foo1"; similarly, all properties will
+ * be included except for the ":childNodeCount" metadata property (see below).
* <p/>
* Glob Syntax:
* <ul>
@@ -298,7 +326,19 @@ public interface MicroKernel {
* If no filter is specified the implicit default filter is assumed:
* {@code {nodes:["*"],properties:["*"]}}
* <p/>
- * For more information see {@link #getNodes(String, String)}.
+ * System-generated metadata properties:
+ * <ul>
+ * <li>{@code :childNodeCount} provides the actual number of direct child nodes; this property
+ * is included by the implicit default filter. it can be excluded by specifying a filter such
+ * as {@code {properties:["*", "-:childNodeCount"]}}</li>
+ * <li>{@code :hash} provides a content-based identifier for the subtree
+ * rooted at the {@code :hash} property's parent node. {@code :hash} values
+ * are similar to fingerprints. they can be compared to quickly determine
+ * if two subtrees are identical. if the {@code :hash} values are different
+ * the respective subtrees are different with regard to structure and/or properties.
+ * {@code :hash} is <i>not</i> included by the implicit default filter.
+ * it can be included by specifying a filter such as {@code {properties:["*", ":hash"]}}</li>
+ * </ul>
*
* @param path path denoting root of node tree to be retrieved
* @param revisionId revision id, if {@code null} the current head revision is assumed
@@ -306,11 +346,10 @@ public interface MicroKernel {
* @param offset start position in the iteration order of child nodes (0 to start at the
* beginning)
* @param count maximum number of child nodes to retrieve (-1 for all)
- * @param filter optional filter on property names; if {@code null} or
+ * @param filter optional filter on property and/or node names; if {@code null} or
* {@code ""} the default filter will be assumed
* @return node tree in JSON format or {@code null} if the specified node does not exist
* @throws MicroKernelException if the specified revision does not exist or if another error occurs
- * @see #getNodes(String, String)
*/
String /* jsonTree */ getNodes(String path, String revisionId, int depth,
long offset, int count, String filter)
Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java?rev=1342226&r1=1342225&r2=1342226&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java Thu May 24 12:28:32 2012
@@ -561,14 +561,42 @@ public class MicroKernelImpl implements
}
}
if (childCount > 0 && depth >= 0) {
+ if (filter != null) {
+ NameFilter childFilter = filter.getChildNodeFilter();
+ if (childFilter != null && !childFilter.containsWildcard()) {
+ // optimization for large child node lists:
+ // no need to iterate over the entire child node list if the filter
+ // does not include wildcards
+ for (String name : childFilter.getInclusionPatterns()) {
+ NodeState child = node.getChildNode(name);
+ if (child != null) {
+ boolean incl = true;
+ for (String exclName : childFilter.getExclusionPatterns()) {
+ if (name.equals(exclName)) {
+ incl = false;
+ break;
+ }
+ }
+ if (incl) {
+ builder.key(name).object();
+ if (depth > 0) {
+ toJson(builder, child, depth - 1, 0, -1, inclVirtualProps, filter);
+ }
+ builder.endObject();
+ }
+ }
+ }
+ return;
+ }
+ }
for (ChildNodeEntry entry : node.getChildNodeEntries(offset, count)) {
if (filter == null || filter.includeNode(entry.getName())) {
builder.key(entry.getName()).object();
if (depth > 0) {
toJson(builder, entry.getNode(), depth - 1, 0, -1, inclVirtualProps, filter);
}
+ builder.endObject();
}
- builder.endObject();
}
}
}
@@ -593,6 +621,7 @@ public class MicroKernelImpl implements
//-------------------------------------------------------< inner classes >
static class NodeFilter {
+
NameFilter nodeFilter;
NameFilter propFilter;
@@ -635,6 +664,14 @@ public class MicroKernelImpl implements
return l.toArray(new String[l.size()]);
}
+ NameFilter getChildNodeFilter() {
+ return nodeFilter;
+ }
+
+ NameFilter getPropertyFilter() {
+ return propFilter;
+ }
+
boolean includeNode(String name) {
return nodeFilter == null ? true : nodeFilter.matches(name);
}
Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java?rev=1342226&r1=1342225&r2=1342226&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/util/NameFilter.java Thu May 24 12:28:32 2012
@@ -51,18 +51,26 @@ public class NameFilter {
// list of ORed inclusion patterns
private final List<String> inclPatterns = new ArrayList<String>();
+
// list of ORed exclusion patterns
private final List<String> exclPatterns = new ArrayList<String>();
+ private boolean containsWildcard;
+
public NameFilter(String[] patterns) {
+ containsWildcard = false;
for (String pattern : patterns) {
if (pattern.isEmpty()) {
continue;
} else if (pattern.charAt(0) == EXCLUDE_PREFIX) {
- exclPatterns.add(pattern.substring(1));
+ pattern = pattern.substring(1);
+ exclPatterns.add(pattern);
} else {
inclPatterns.add(pattern);
}
+ if (!containsWildcard) {
+ containsWildcard = containsWildCard(pattern);
+ }
}
}
@@ -87,6 +95,36 @@ public class NameFilter {
return matched;
}
+ public boolean containsWildcard() {
+ return containsWildcard;
+ }
+
+ public List<String> getExclusionPatterns() {
+ return exclPatterns;
+ }
+
+ public List<String> getInclusionPatterns() {
+ return inclPatterns;
+ }
+
+ private static boolean containsWildCard(String pattern) {
+ int len = pattern.length();
+ int pos = 0;
+ while (pos < len) {
+ if (pattern.charAt(pos) == ESCAPE
+ && pos < (len - 1)
+ && pattern.charAt(pos + 1) == WILDCARD) {
+ pos += 2;
+ continue;
+ }
+ if (pattern.charAt(pos) == WILDCARD) {
+ return true;
+ }
+ pos++;
+ }
+ return false;
+ }
+
/**
* Internal helper used to recursively match the pattern
*
Modified: jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java?rev=1342226&r1=1342225&r2=1342226&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/test/java/org/apache/jackrabbit/mk/util/NameFilterTest.java Thu May 24 12:28:32 2012
@@ -34,47 +34,58 @@ public class NameFilterTest {
assertTrue(filter.matches("foo bar"));
assertTrue(filter.matches("foo 99"));
assertFalse(filter.matches("foo99"));
+ assertTrue(filter.containsWildcard());
filter = new NameFilter(new String[]{"*foo"});
assertTrue(filter.matches("foo"));
assertTrue(filter.matches("-123foo"));
assertFalse(filter.matches("bar"));
+ assertTrue(filter.containsWildcard());
filter = new NameFilter(new String[]{"foo\\*bar"});
assertFalse(filter.matches("foo bar"));
assertTrue(filter.matches("foo*bar"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"foo\\bar"});
assertTrue(filter.matches("foo\\bar"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"foo\\"});
assertTrue(filter.matches("foo\\"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"*"});
assertTrue(filter.matches("*"));
assertTrue(filter.matches("\\*"));
assertTrue(filter.matches("blah"));
+ assertTrue(filter.containsWildcard());
filter = new NameFilter(new String[]{"\\*"});
assertTrue(filter.matches("*"));
assertFalse(filter.matches("\\*"));
assertFalse(filter.matches("blah"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"\\- topic"});
assertTrue(filter.matches("- topic"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"*", "- topic"});
assertFalse(filter.matches(" topic"));
assertTrue(filter.matches("- topic"));
assertTrue(filter.matches("blah"));
+ assertTrue(filter.containsWildcard());
filter = new NameFilter(new String[]{"foo\\-bar"});
assertFalse(filter.matches("foo-bar"));
assertTrue(filter.matches("foo\\-bar"));
+ assertFalse(filter.containsWildcard());
filter = new NameFilter(new String[]{"foo\\\\*bar"});
assertTrue(filter.matches("foo\\*bar"));
assertFalse(filter.matches("foo\\ blah bar"));
assertFalse(filter.matches("foo*bar"));
+ assertFalse(filter.containsWildcard());
}
}