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 md...@apache.org on 2012/04/03 12:32:48 UTC

svn commit: r1308805 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/ oak-mk/src/main/java/org/apache/jackrabbit/mk/model/

Author: mduerig
Date: Tue Apr  3 10:32:48 2012
New Revision: 1308805

URL: http://svn.apache.org/viewvc?rev=1308805&view=rev
Log:
OAK-9: Internal tree builder
Initial implementation of NodeStateEditor (WIP)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateEditor.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ConnectionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStateEditor.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStore.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ConnectionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ConnectionImpl.java?rev=1308805&r1=1308804&r2=1308805&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ConnectionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ConnectionImpl.java Tue Apr  3 10:32:48 2012
@@ -101,13 +101,13 @@ public class ConnectionImpl implements C
     @Override
     public NodeState commit(NodeStateEditor editor) throws CommitFailedException {
         if (workspaceName == null) {
-// todo            merge changes from editor into base
             return root = store.getRoot();
         }
         else {
-// todo            merge changes from editor into base
             return root = store.getRoot().getChildNode(workspaceName);
         }
+
+        // todo return store.merge(editor, editor.getBaseNodeState());
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java?rev=1308805&r1=1308804&r2=1308805&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java Tue Apr  3 10:32:48 2012
@@ -206,6 +206,16 @@ class KernelNodeState extends AbstractNo
         return entries;
     }
 
+    //------------------------------------------------------------< internal >---
+
+    String getRevision() {
+        return revision;
+    }
+
+    String getPath() {
+        return path;
+    }
+
     private String getChildPath(String name) {
         if ("/".equals(path)) {
             return '/' + name;

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateEditor.java?rev=1308805&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateEditor.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateEditor.java Tue Apr  3 10:32:48 2012
@@ -0,0 +1,365 @@
+/*
+ * 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.oak.kernel;
+
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.model.AbstractChildNodeEntry;
+import org.apache.jackrabbit.mk.model.AbstractNodeState;
+import org.apache.jackrabbit.mk.model.ChildNodeEntry;
+import org.apache.jackrabbit.mk.model.NodeState;
+import org.apache.jackrabbit.mk.model.NodeStateEditor;
+import org.apache.jackrabbit.mk.model.PropertyState;
+import org.apache.jackrabbit.mk.util.PathUtils;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+public class KernelNodeStateEditor implements NodeStateEditor {
+    private final NodeState base;
+    private final String path;
+    private final StringBuilder jsop;
+
+    private final Map<String, NodeState> addedNodes = new HashMap<String, NodeState>();
+    private final Set<String> removedNodes = new HashSet<String>();
+    private final Map<String, PropertyState> addedProperties = new HashMap<String, PropertyState>();
+    private final Set<String> removedProperties = new HashSet<String>();
+
+    KernelNodeStateEditor(NodeState base) {
+        this.base = base;
+        this.path = "";
+        this.jsop = new StringBuilder();
+    }
+
+    private KernelNodeStateEditor(NodeState base, String path, StringBuilder jsop) {
+        this.base = base;
+        this.path = path;
+        this.jsop = jsop;
+    }
+
+    @Override
+    public void addNode(String name) {
+        if (!hasNodeState(name)) {
+            transientAddNode(name, new TransientNodeState(name));
+            jsop.append("+\"").append(path(name)).append("\":{}");
+        }
+    }
+
+    @Override
+    public void removeNode(String name) {
+        if (hasNodeState(name)) {
+            transientRemoveNode(name);
+            jsop.append("-\"").append(path(name)).append('"');
+        }
+    }
+
+    @Override
+    public void setProperty(PropertyState state) {
+        transientSetProperty(state);
+        jsop.append("^\"").append(path(state.getName())).append("\":")
+                .append(state.getEncodedValue());
+    }
+
+    @Override
+    public void removeProperty(String name) {
+        transientRemoveProperty(name);
+        jsop.append("^\"").append(path(name)).append("\":null");
+    }
+
+    @Override
+    public void move(String sourcePath, String destPath) {
+        KernelNodeStateEditor sourceParent = getEditor(PathUtils.getAncestorPath(sourcePath, 1));
+        String sourceName = PathUtils.getName(sourcePath);
+        if (sourceParent == null || !sourceParent.hasNodeState(sourceName)) {
+            return;
+        }
+        
+        KernelNodeStateEditor destParent = getEditor(PathUtils.getAncestorPath(destPath, 1));
+        String destName = PathUtils.getName(destPath);
+        if (destParent == null || destParent.hasNodeState(destName)) {
+            return;
+        }
+
+        destParent.transientAddNode(destName, sourceParent.transientRemoveNode(sourceName));
+        jsop.append(">\"").append(path(sourcePath))
+                .append("\":\"").append(path(destPath)).append('"');
+    }
+
+    @Override
+    public void copy(String sourcePath, String destPath) {
+        KernelNodeStateEditor source = getEditor(sourcePath);
+        if (source == null) {
+            return;
+        }
+
+        KernelNodeStateEditor destParent = getEditor(PathUtils.getAncestorPath(destPath, 1));
+        String destName = PathUtils.getName(destPath);
+        if (destParent == null || destParent.hasNodeState(destName)) {
+            return;
+        }
+
+        destParent.transientAddNode(destName, source.getNodeState());
+        jsop.append("*\"").append(path(sourcePath)).append("\":\"")
+                .append(path(destPath)).append('"');
+    }
+
+    @Override
+    public KernelNodeStateEditor edit(String name) {
+        NodeState childState = getChildNodeState(name);
+        if (childState == null) {
+            return null;
+        }
+        else if (childState instanceof TransientNodeState) {
+            return ((TransientNodeState) childState).editor;
+        }
+        else {
+            return new KernelNodeStateEditor(childState, cat(path, name), jsop);
+        }
+    }
+
+    @Override
+    public NodeState getNodeState() {
+        return new TransientNodeState(this);
+    }
+
+    @Override
+    public NodeState getBaseNodeState() {
+        return base;
+    }
+
+    //------------------------------------------------------------< internal >---
+
+    NodeState mergeInto(MicroKernel microkernel, KernelNodeState target) {
+        String targetPath = target.getRevision();
+        String targetRevision = target.getPath();
+        String rev = microkernel.commit(targetPath, jsop.toString(), targetRevision, null);
+        return new KernelNodeState(microkernel, targetPath, rev);
+    }
+
+    private KernelNodeStateEditor getEditor(String path) {
+        KernelNodeStateEditor editor = this;
+        for(String name : PathUtils.elements(path)) {
+            editor = editor.edit(name);
+            if (editor == null) {
+                return null;
+            }
+        }
+        
+        return editor;
+    }
+
+    private static String cat(String path, String relPath) {
+        return path.isEmpty() ? relPath : path + '/' + relPath;
+    }
+
+    private String path(String name) {
+        return cat(path, name);
+    }
+
+    private NodeState getChildNodeState(String name) {
+        NodeState state = addedNodes.get(name);
+        if (state != null) {
+            return state;
+        }
+
+        return removedNodes.contains(name)
+            ? null
+            : base.getChildNode(name);
+    }
+
+    private boolean hasNodeState(String name) {
+        return getChildNodeState(name) != null;
+    }
+
+    private PropertyState getPropertyState(String name) {
+        PropertyState state = addedProperties.get(name);
+        if (state != null) {
+            return state;
+        }
+
+        if (removedProperties.contains(name)) {
+            return null;
+        }
+        else {
+            return base.getProperty(name);
+        }
+    }
+
+    private void transientAddNode(String name, NodeState nodeState) {
+        addedNodes.put(name, nodeState);
+    }
+
+    private NodeState transientRemoveNode(String name) {
+        NodeState state = addedNodes.remove(name);
+        removedNodes.add(name);
+        return state == null
+            ? base.getChildNode(name)
+            : state;
+    }
+
+    private void transientSetProperty(PropertyState state) {
+        addedProperties.put(state.getName(), state);
+    }
+
+    private void transientRemoveProperty(String name) {
+        addedProperties.remove(name);
+        removedProperties.add(name);
+    }
+
+    private class TransientNodeState extends AbstractNodeState {
+        private final KernelNodeStateEditor editor;
+
+        public TransientNodeState(KernelNodeStateEditor editor) {
+            this.editor = editor;
+        }
+
+        public TransientNodeState(String name) {
+            this.editor = new KernelNodeStateEditor(this, cat(path, name), jsop);
+        }
+
+        @Override
+        public PropertyState getProperty(String name) {
+            return editor.getPropertyState(name);
+        }
+
+        @Override
+        public NodeState getChildNode(String name) {
+            return editor.getChildNodeState(name);
+        }
+
+        @Override
+        public Iterable<? extends PropertyState> getProperties() {
+            final Set<String> removed = new HashSet<String>();
+            removed.addAll(editor.removedProperties);
+
+            final Map<String, PropertyState> added = new HashMap<String, PropertyState>();
+            added.putAll(editor.addedProperties);
+
+            final Iterable<? extends PropertyState> baseProperties = editor.base.getProperties();
+            return new Iterable<PropertyState>() {
+                @Override
+                public Iterator<PropertyState> iterator() {
+                    return new Iterator<PropertyState>() {
+                        private final Iterator<? extends PropertyState> properties = baseProperties.iterator();
+                        private PropertyState next;
+
+                        @Override
+                        public boolean hasNext() {
+                            if (next == null) {
+                                while (properties.hasNext()) {
+                                    PropertyState prop = properties.next();
+                                    if (added.containsKey(prop.getName())) {
+                                        next = added.get(prop.getName());
+                                        break;
+                                    }
+                                    if (!removed.contains(prop.getName())) {
+                                        next = prop;
+                                        break;
+                                    }
+                                }
+                            }
+                            return next != null;
+                        }
+
+                        @Override
+                        public PropertyState next() {
+                            if (!hasNext()) {
+                                throw new NoSuchElementException();
+                            }
+                            PropertyState e = next;
+                            next = null;
+                            return e;
+                        }
+
+                        @Override
+                        public void remove() {
+                            throw new UnsupportedOperationException("remove");
+                        }
+                    };
+                }
+            };
+        }
+
+        @Override
+        public Iterable<? extends ChildNodeEntry> getChildNodeEntries(long offset, int count) {
+            final Set<String> removed = new HashSet<String>();
+            removed.addAll(editor.removedNodes);
+
+            final Map<String, NodeState> added = new HashMap<String, NodeState>();
+            added.putAll(editor.addedNodes);
+
+            final Iterable<? extends ChildNodeEntry> baseNodes = editor.base.getChildNodeEntries(offset, count);
+            return new Iterable<ChildNodeEntry>() {
+                @Override
+                public Iterator<ChildNodeEntry> iterator() {
+                    return new Iterator<ChildNodeEntry>() {
+                        private final Iterator<? extends ChildNodeEntry> properties = baseNodes.iterator();
+                        private ChildNodeEntry next;
+
+                        @Override
+                        public boolean hasNext() {
+                            if (next == null) {
+                                while (properties.hasNext()) {
+                                    final ChildNodeEntry entry = properties.next();
+                                    if (added.containsKey(entry.getName())) {
+                                        next = new AbstractChildNodeEntry() {
+                                            @Override
+                                            public String getName() {
+                                                return entry.getName();
+                                            }
+
+                                            @Override
+                                            public NodeState getNode() {
+                                                return added.get(entry.getName());
+                                            }
+                                        };
+                                        break;
+                                    }
+                                    if (!removed.contains(entry.getName())) {
+                                        next = entry;
+                                        break;
+                                    }
+                                }
+                            }
+                            return next != null;
+                        }
+
+                        @Override
+                        public ChildNodeEntry next() {
+                            if (!hasNext()) {
+                                throw new NoSuchElementException();
+                            }
+                            ChildNodeEntry e = next;
+                            next = null;
+                            return e;
+                        }
+
+                        @Override
+                        public void remove() {
+                            throw new UnsupportedOperationException("remove");
+                        }
+                    };
+                }
+            };
+        }
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java?rev=1308805&r1=1308804&r2=1308805&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java Tue Apr  3 10:32:48 2012
@@ -41,12 +41,19 @@ public class KernelNodeStore implements 
 
     @Override
     public NodeStateEditor branch(NodeState base) {
-        return null; // todo implement branch
+        return new KernelNodeStateEditor(base);
     }
 
     @Override
-    public NodeState merge(NodeStateEditor branch, NodeState base) {
-        return null; // todo implement merge
+    public NodeState merge(NodeStateEditor branch, NodeState target) {
+        if (!(branch instanceof KernelNodeStateEditor)) {
+            throw new IllegalArgumentException("Branch does not belong to this store");
+        }
+        if (!(target instanceof KernelNodeStore)) {
+            throw new IllegalArgumentException("Target does not belong to this store");
+        }
+
+        return ((KernelNodeStateEditor) branch).mergeInto(kernel, (KernelNodeState) target);
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStateEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStateEditor.java?rev=1308805&r1=1308804&r2=1308805&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStateEditor.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStateEditor.java Tue Apr  3 10:32:48 2012
@@ -25,24 +25,24 @@ package org.apache.jackrabbit.mk.model;
 public interface NodeStateEditor {
 
     /**
-     * Add or replace the child node state with the given {@code name}.
+     * Add the child node state with the given {@code name}. Does nothing
+     * if such a child node already exists.
      * @param name name of the new node state
-     * @return editor for the added node state
      */
-    NodeStateEditor addNode(String name);
+    void addNode(String name);
 
     /**
-     * Remove the child node state with the given {@code name}.
+     * Remove the child node state with the given {@code name}. Does nothing
+     * if no such child node exists.
      * @param name  name of the node state to remove
      */
     void removeNode(String name);
 
     /**
      * Set a property on this node state
-     * @param name name of the property
-     * @param value value of the property
+     * @param state property state to set
      */
-    void setProperty(String name, Scalar value);
+    void setProperty(PropertyState state);
 
     /**
      * Remove a property from this node state

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStore.java?rev=1308805&r1=1308804&r2=1308805&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/model/NodeStore.java Tue Apr  3 10:32:48 2012
@@ -49,14 +49,14 @@ public interface NodeStore {
     NodeStateEditor branch(NodeState base);
 
     /**
-     * Atomically merges the changes from {@code branch} back
-     * into the sub-tree rooted at {@code base}.
+     * Atomically merges the changes from {@code branch} back into the
+     * {@code target}.
      *
-     * @param branch branch to merge into {@code base}
-     * @param base base of the sub-tree for merging
-     * @return result of the merge operation: the new node state of the
-     *         sub tree rooted at {@code base}.
+     * @param branch branch for merging into {@code target}
+     * @param target target of the merge operation
+     * @return node state resulting from merging {@code branch} into
+     *         {@code target}.
      */
-    NodeState merge(NodeStateEditor branch, NodeState base);
+    NodeState merge(NodeStateEditor branch, NodeState target);
 
 }