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