Author: chetanm
Date: Wed Oct 19 15:07:30 2016
New Revision: 1765623

URL: http://svn.apache.org/viewvc?rev=1765623&view=rev
Log:
OAK-1312 -  [bundling] Bundle nodes into a document

Implement read part of bundling

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/bundlor/DocumentBundlingTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1765623&r1=1765622&r2=1765623&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 Wed Oct 19 15:07:30 2016
@@ -41,6 +41,9 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.commons.json.JsopWriter;
 import org.apache.jackrabbit.oak.json.JsonSerializer;
+import org.apache.jackrabbit.oak.plugins.document.bundlor.BundlorUtils;
+import org.apache.jackrabbit.oak.plugins.document.bundlor.DocumentBundlor;
+import org.apache.jackrabbit.oak.plugins.document.bundlor.Matcher;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
@@ -81,6 +84,7 @@ public class DocumentNodeState extends A
     private final boolean hasChildren;
 
     private final DocumentNodeStore store;
+    private BundlingContext bundlingContext;
 
     private AbstractDocumentNodeState cachedSecondaryState;
 
@@ -106,13 +110,28 @@ public class DocumentNodeState extends A
                               boolean hasChildren,
                               @Nullable RevisionVector lastRevision,
                               boolean fromExternalChange) {
+        this(store, path, hasChildren, rootRevision, lastRevision,
+                fromExternalChange, 
createBundlingContext(checkNotNull(properties)));
+    }
+
+    private DocumentNodeState(@Nonnull DocumentNodeStore store,
+                              @Nonnull String path,
+                              boolean hasChildren,
+                              @Nonnull RevisionVector rootRevision,
+                              @Nullable RevisionVector lastRevision,
+                              boolean fromExternalChange,
+                              BundlingContext bundlingContext) {
         this.store = checkNotNull(store);
         this.path = checkNotNull(path);
         this.rootRevision = checkNotNull(rootRevision);
         this.lastRevision = lastRevision;
         this.fromExternalChange = fromExternalChange;
-        this.hasChildren = hasChildren;
-        this.properties = checkNotNull(properties);
+        this.properties = bundlingContext.getProperties();
+        this.bundlingContext = bundlingContext;
+
+        //TODO [bundling] hasChildren optimization
+        this.hasChildren = this.bundlingContext.matcher.isMatch() || 
hasChildren;
+
     }
 
     /**
@@ -237,9 +256,12 @@ public class DocumentNodeState extends A
         if (!hasChildren) {
             return 0;
         }
+
+        //TODO [bundling] Optimize if matcher matches all child
+
         if (max > DocumentNodeStore.NUM_CHILDREN_CACHE_LIMIT) {
             // count all
-            return Iterators.size(new ChildNodeEntryIterator());
+            return Iterables.size(getChildNodeEntries());
         }
         Children c = store.getChildren(this, null, (int) max);
         if (c.hasMore) {
@@ -267,10 +289,12 @@ public class DocumentNodeState extends A
             return secondaryState.getChildNodeEntries();
         }
 
+        //TODO [bundling] Optimize if matcher matches all child
+
         return new Iterable<ChildNodeEntry>() {
             @Override
             public Iterator<ChildNodeEntry> iterator() {
-                return new ChildNodeEntryIterator();
+                return Iterators.concat(getBundledChildren(), new 
ChildNodeEntryIterator());
             }
         };
     }
@@ -414,6 +438,16 @@ public class DocumentNodeState extends A
             }
             return null;
         }
+
+        Matcher child = bundlingContext.matcher.next(childNodeName);
+        if (child.isMatch()){
+            if (bundlingContext.hasChildNode(child.getMatchedPath())){
+                return createBundledState(childNodeName, child);
+            } else {
+                return null;
+            }
+        }
+
         return store.getNode(PathUtils.concat(getPath(), childNodeName), 
lastRevision);
     }
 
@@ -478,6 +512,7 @@ public class DocumentNodeState extends A
         if (hasChildren) {
             json.key("hasChildren").value(true);
         }
+        //TODO [bundling] Handle serialization
         if (properties.size() > 0) {
             json.key("prop").object();
             for (String k : properties.keySet()) {
@@ -668,4 +703,80 @@ public class DocumentNodeState extends A
         }
     }
 
+    //~----------------------------------------------< Bundling >
+
+    private AbstractDocumentNodeState createBundledState(String childNodeName, 
Matcher child) {
+        return new DocumentNodeState(
+                store,
+                PathUtils.concat(path, childNodeName),
+                true, //TODO Determine child node
+                lastRevision,
+                rootRevision,
+                fromExternalChange,
+                bundlingContext.childContext(child));
+    }
+
+    private Iterator<ChildNodeEntry> getBundledChildren(){
+        return 
Iterators.transform(bundlingContext.getBundledChildNodeNames().iterator(),
+                new Function<String, ChildNodeEntry>() {
+            @Override
+            public ChildNodeEntry apply(final String childNodeName) {
+                return new AbstractChildNodeEntry() {
+                    @Nonnull
+                    @Override
+                    public String getName() {
+                        return childNodeName;
+                    }
+
+                    @Nonnull
+                    @Override
+                    public NodeState getNodeState() {
+                        return createBundledState(childNodeName, 
bundlingContext.matcher.next(childNodeName));
+                    }
+                };
+            }
+        });
+    }
+
+    private static BundlingContext createBundlingContext(Map<String, 
PropertyState> properties) {
+        PropertyState bundlorConfig = 
properties.get(DocumentBundlor.META_PROP_PATTERN);
+        Matcher matcher = Matcher.NON_MATCHING;
+        if (bundlorConfig != null){
+            matcher = DocumentBundlor.from(bundlorConfig).createMatcher();
+        }
+        return new BundlingContext(matcher, properties);
+    }
+
+    private static class BundlingContext {
+        final Matcher matcher;
+        final Map<String, PropertyState> rootProperties;
+
+        public BundlingContext(Matcher matcher, Map<String, PropertyState> 
rootProperties) {
+            this.matcher = matcher;
+            this.rootProperties = rootProperties;
+        }
+
+        public BundlingContext childContext(Matcher childMatcher){
+            return new BundlingContext(childMatcher, rootProperties);
+        }
+
+        public Map<String, PropertyState> getProperties(){
+            if (matcher.isMatch()){
+                return BundlorUtils.getMatchingProperties(rootProperties, 
matcher);
+            }
+            return rootProperties;
+        }
+
+        public boolean hasChildNode(String relativePath){
+            String key = PathUtils.concat(relativePath, 
DocumentBundlor.META_PROP_NODE);
+            return rootProperties.containsKey(key);
+        }
+
+        public List<String> getBundledChildNodeNames(){
+            if (matcher.isMatch()) {
+                return BundlorUtils.getChildNodeNames(rootProperties.keySet(), 
matcher);
+            }
+            return Collections.emptyList();
+        }
+    }
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/bundlor/DocumentBundlingTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/bundlor/DocumentBundlingTest.java?rev=1765623&r1=1765622&r2=1765623&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/bundlor/DocumentBundlingTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/bundlor/DocumentBundlingTest.java
 Wed Oct 19 15:07:30 2016
@@ -19,18 +19,20 @@
 
 package org.apache.jackrabbit.oak.plugins.document.bundlor;
 
+import java.util.Set;
+
+import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.plugins.document.Collection;
 import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
-import org.apache.jackrabbit.oak.spi.commit.CompositeHook;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.state.EqualsDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -57,7 +59,6 @@ public class DocumentBundlingTest {
         store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
     }
 
-    @Ignore("Read part not yet implemented")
     @Test
     public void saveAndReadNtFile() throws Exception{
         NodeBuilder builder = store.getRoot().builder();
@@ -71,7 +72,10 @@ public class DocumentBundlingTest {
 
         NodeState root = store.getRoot();
         NodeState fileNodeState = root.getChildNode("test");
-        assertTrue(EqualsDiff.equals(fileNode.getNodeState(), fileNodeState));
+        assertTrue(fileNodeState.getChildNode("book.jpg").exists());
+        
assertTrue(fileNodeState.getChildNode("book.jpg").getChildNode("jcr:content").exists());
+
+        assertTrue(PartialEqualsDiff.equals(fileNode.getNodeState(), 
fileNodeState.getChildNode("book.jpg")));
     }
 
     private static NodeBuilder newNode(String typeName){
@@ -79,4 +83,35 @@ public class DocumentBundlingTest {
         builder.setProperty(JCR_PRIMARYTYPE, typeName);
         return builder;
     }
+
+    private static class PartialEqualsDiff extends EqualsDiff {
+        private final Set<String> ignoredProps = 
Sets.newHashSet(DocumentBundlor.META_PROP_PATTERN);
+
+        public static boolean equals(NodeState before, NodeState after) {
+            return before.exists() == after.exists()
+                    && after.compareAgainstBaseState(before, new 
PartialEqualsDiff());
+        }
+
+        @Override
+        public boolean propertyAdded(PropertyState after) {
+            if (ignore(after)) return true;
+            return super.propertyAdded(after);
+        }
+
+        @Override
+        public boolean propertyChanged(PropertyState before, PropertyState 
after) {
+            if (ignore(after)) return true;
+            return super.propertyChanged(before, after);
+        }
+
+        @Override
+        public boolean propertyDeleted(PropertyState before) {
+            if (ignore(before)) return true;
+            return super.propertyDeleted(before);
+        }
+
+        private boolean ignore(PropertyState state){
+            return ignoredProps.contains(state.getName());
+        }
+    }
 }


Reply via email to