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());
     }
 }