You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2011/09/02 16:53:37 UTC

svn commit: r1164559 - in /jackrabbit/sandbox/microkernel/src: main/java/org/apache/jackrabbit/mk/ main/java/org/apache/jackrabbit/mk/index/ main/java/org/apache/jackrabbit/mk/json/ main/java/org/apache/jackrabbit/mk/mem/ test/java/org/apache/jackrabbi...

Author: thomasm
Date: Fri Sep  2 14:53:36 2011
New Revision: 1164559

URL: http://svn.apache.org/viewvc?rev=1164559&view=rev
Log:
Trying to support large child node lists (WIP);
Slightly improved Jsop builder and tokenizer.

Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTree.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/IndexNode.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java
    jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java Fri Sep  2 14:53:36 2011
@@ -182,46 +182,46 @@ public class MicroKernelImpl implements 
 
                 NodeUtils.diff(path, node1, node2, true, rep.getPersistenceManager(), new NodeDiffHandler() {
                     public void propAdded(String nodePath, String propName, String value) {
-                        buff.append("+ ").
+                        buff.appendTag("+ ").
                                 key(PathUtils.concat(nodePath, propName)).
                                 encodedValue(value).
-                                appendWhitespace("\n");
+                                newline();
                     }
 
                     public void propChanged(String nodePath, String propName, String oldValue, String newValue) {
-                        buff.append("^ ").
+                        buff.appendTag("^ ").
                                 key(PathUtils.concat(nodePath, propName)).
                                 encodedValue(newValue).
-                                appendWhitespace("\n");
+                                newline();
                     }
 
                     public void propDeleted(String nodePath, String propName, String value) {
                         // since property and node deletions can't be distinguished
                         // using the "- <path>" notation we're representing
                         // property deletions as "^ <path>:null"
-                        buff.append("^ ").
+                        buff.appendTag("^ ").
                                 key(PathUtils.concat(nodePath, propName)).
                                 encodedValue("null").
-                                appendWhitespace("\n");
+                                newline();
                     }
 
                     public void childNodeAdded(String nodePath, String childName, String id) {
                         addedNodes.put(id, PathUtils.concat(nodePath, childName));
-                        buff.append("+ ").
+                        buff.appendTag("+ ").
                                 key(PathUtils.concat(nodePath, childName)).object();
                         try {
                             toJson(buff, rep.getPersistenceManager().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
                         } catch (Exception e) {
                             buff.value("ERROR: failed to retrieve node " + id);
                         }
-                        buff.endObject().appendWhitespace("\n");
+                        buff.endObject().newline();
                     }
 
                     public void childNodeDeleted(String nodePath, String childName, String id) {
                         removedNodes.put(id, PathUtils.concat(nodePath, childName));
-                        buff.append("- ");
+                        buff.appendTag("- ");
                         buff.value(PathUtils.concat(nodePath, childName));
-                        buff.appendWhitespace("\n");
+                        buff.newline();
                     }
 
                     public void childNodeChanged(String nodePath, String childName, String oldId, String newId) {
@@ -243,27 +243,27 @@ public class MicroKernelImpl implements 
                     // TODO refactor code, avoid duplication
                     NodeUtils.diff(path, node1, node2, true, rep.getPersistenceManager(), new NodeDiffHandler() {
                         public void propAdded(String nodePath, String propName, String value) {
-                            buff.append("+ ").
+                            buff.appendTag("+ ").
                                     key(PathUtils.concat(nodePath, propName)).
                                     encodedValue(value).
-                                    append("\n");
+                                    appendTag("\n");
                         }
 
                         public void propChanged(String nodePath, String propName, String oldValue, String newValue) {
-                            buff.append("^ ").
+                            buff.appendTag("^ ").
                                     key(PathUtils.concat(nodePath, propName)).
                                     encodedValue(newValue).
-                                    append("\n");
+                                    appendTag("\n");
                         }
 
                         public void propDeleted(String nodePath, String propName, String value) {
                             // since property and node deletions can't be distinguished
                             // using the "- <path>" notation we're representing
                             // property deletions as "^ <path>:null"
-                            buff.append("^ ").
+                            buff.appendTag("^ ").
                                     key(PathUtils.concat(nodePath, propName)).
                                     encodedValue("null").
-                                    append("\n");
+                                    appendTag("\n");
                         }
 
                         public void childNodeAdded(String nodePath, String childName, String id) {
@@ -271,14 +271,14 @@ public class MicroKernelImpl implements 
                                 // moved node, will be processed separately
                                 return;
                             }
-                            buff.append("+ ").
+                            buff.appendTag("+ ").
                                     key(PathUtils.concat(nodePath, childName)).object();
                             try {
                                 toJson(buff, rep.getPersistenceManager().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
                             } catch (Exception e) {
                                 buff.value("ERROR: failed to retrieve node " + id);
                             }
-                            buff.endObject().append("\n");
+                            buff.endObject().appendTag("\n");
                         }
 
                         public void childNodeDeleted(String nodePath, String childName, String id) {
@@ -286,9 +286,9 @@ public class MicroKernelImpl implements 
                                 // moved node, will be processed separately
                                 return;
                             }
-                            buff.append("- ");
+                            buff.appendTag("- ");
                             buff.value(PathUtils.concat(nodePath, childName));
-                            buff.append("\n");
+                            buff.appendTag("\n");
                         }
 
                         public void childNodeChanged(String nodePath, String childName, String oldId, String newId) {
@@ -297,12 +297,12 @@ public class MicroKernelImpl implements 
                     });
                     // finally process moved nodes
                     for (Map.Entry<String, String> entry : addedNodes.entrySet()) {
-                        buff.append("> ").
+                        buff.appendTag("> ").
                                 // path/to/deleted/node
                                         key(removedNodes.get(entry.getKey())).
                                 // path/to/added/node
                                         value(entry.getValue()).
-                                append("\n");
+                                newline();
                     }
                 }
             } catch (Exception e) {

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTree.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTree.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTree.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTree.java Fri Sep  2 14:53:36 2011
@@ -40,7 +40,7 @@ public class BTree {
 
         if (!indexer.nodeExists(name)) {
             JsopBuilder jsop = new JsopBuilder();
-            jsop.append("+ ").key(name).append("{}");
+            jsop.appendTag("+ ").key(name).encodedValue("{}");
             indexer.commit(jsop.toString());
         }
     }
@@ -148,9 +148,9 @@ public class BTree {
     void bufferSetArray(String path, String propertyName, String[] data) {
         JsopBuilder jsop = new JsopBuilder();
         path = PathUtils.concat(name, path);
-        jsop.append("^ ").key(PathUtils.concat(path, propertyName));
+        jsop.appendTag("^ ").key(PathUtils.concat(path, propertyName));
         if (data.length == 0) {
-            jsop.append(null);
+            jsop.value(null);
         } else {
             jsop.array();
             for (String d : data) {
@@ -158,21 +158,21 @@ public class BTree {
             }
             jsop.endArray();
         }
-        jsop.appendWhitespace("\n");
+        jsop.newline();
         indexer.buffer(jsop.toString());
     }
 
     void bufferMove(String path, String newPath) {
         JsopBuilder jsop = new JsopBuilder();
-        jsop.append("> ").key(path).value(newPath);
-        jsop.appendWhitespace("\n");
+        jsop.appendTag("> ").key(path).value(newPath);
+        jsop.newline();
         indexer.buffer(jsop.toString());
     }
 
     void bufferDelete(String path) {
         JsopBuilder jsop = new JsopBuilder();
-        jsop.append("- ").value(PathUtils.concat(name, path));
-        jsop.appendWhitespace("\n");
+        jsop.appendTag("- ").value(PathUtils.concat(name, path));
+        jsop.newline();
         indexer.buffer(jsop.toString());
     }
 

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/BTreeLeaf.java Fri Sep  2 14:53:36 2011
@@ -65,7 +65,7 @@ class BTreeLeaf extends BTreePage {
 
     void writeCreate() {
         JsopBuilder jsop = new JsopBuilder();
-        jsop.append("+ ").key(PathUtils.concat(tree.getName(), getPath())).object();
+        jsop.appendTag("+ ").key(PathUtils.concat(tree.getName(), getPath())).object();
         jsop.key("keys").array();
         for (String k : keys) {
             jsop.value(k);
@@ -77,7 +77,7 @@ class BTreeLeaf extends BTreePage {
         }
         jsop.endArray();
         jsop.endObject();
-        jsop.appendWhitespace("\n");
+        jsop.newline();
         tree.buffer(jsop.toString());
     }
 

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/IndexNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/IndexNode.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/IndexNode.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/IndexNode.java Fri Sep  2 14:53:36 2011
@@ -92,7 +92,7 @@ class IndexNode extends BTreePage {
 
     void writeCreate() {
         JsopBuilder jsop = new JsopBuilder();
-        jsop.append("+ ").key(PathUtils.concat(tree.getName(), getPath())).object();
+        jsop.appendTag("+ ").key(PathUtils.concat(tree.getName(), getPath())).object();
         jsop.key("keys").array();
         for (String k : keys) {
             jsop.value(k);
@@ -113,7 +113,7 @@ class IndexNode extends BTreePage {
         }
         jsop.endArray();
         jsop.endObject();
-        jsop.appendWhitespace("\n");
+        jsop.newline();
         tree.buffer(jsop.toString());
     }
 

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java Fri Sep  2 14:53:36 2011
@@ -52,7 +52,7 @@ public class Indexer {
         readRevision = revision;
         if (!mk.nodeExists(indexRootNode, revision)) {
             JsopBuilder jsop = new JsopBuilder();
-            jsop.append("+ ").key(PathUtils.relativize("/", indexRootNode)).append("{}");
+            jsop.appendTag("+ ").key(PathUtils.relativize("/", indexRootNode)).encodedValue("{}");
             revision = mk.commit("/", jsop.toString(), revision, null);
         } else {
             String node = mk.getNodes(indexRootNode, revision, 0, 0, 0);
@@ -197,7 +197,7 @@ public class Indexer {
         } while (t.matches(','));
         readRevision = toRevision;
         JsopBuilder jsop = new JsopBuilder();
-        jsop.append("^ ").key("rev").value(readRevision);
+        jsop.appendTag("^ ").key("rev").value(readRevision);
         buffer(jsop.toString());
         commit();
     }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java Fri Sep  2 14:53:36 2011
@@ -28,6 +28,7 @@ public class JsopBuilder {
 
     private StringBuilder buff = new StringBuilder();
     private boolean needComma;
+    private int lineLength, previous;
 
     /**
      * Resets this instance.
@@ -37,17 +38,19 @@ public class JsopBuilder {
         buff.setLength(0);
     }
 
+    public void setLineLength(int length) {
+        lineLength = length;
+    }
+
     /**
-     * Append an already formatted string. This will reset the comma flag, so no
-     * comma is added before the next key or value.
+     * Append an (already formatted) Jsop tag. This will allow to append
+     * non-Json data. This method resets the comma flag, so no comma is added
+     * before the next key or value.
      *
      * @param string the string to append
      * @return this
      */
-    public JsopBuilder append(String string) {
-        int todoThisIsALeakyAbstraction;
-        // TODO the user should not have to think about whether to use
-        // append or appendWhitespace.
+    public JsopBuilder appendTag(String string) {
         buff.append(string);
         needComma = false;
         return this;
@@ -60,8 +63,8 @@ public class JsopBuilder {
      * @param string the string to append
      * @return this
      */
-    public JsopBuilder appendWhitespace(String string) {
-        buff.append(string);
+    public JsopBuilder newline() {
+        buff.append('\n');
         return this;
     }
 
@@ -71,7 +74,7 @@ public class JsopBuilder {
      * @return this
      */
     public JsopBuilder object() {
-        optionalComma();
+        optionalCommaAndNewline(1);
         buff.append('{');
         needComma = false;
         return this;
@@ -98,7 +101,7 @@ public class JsopBuilder {
      * @return this
      */
     public JsopBuilder array() {
-        optionalComma();
+        optionalCommaAndNewline(1);
         buff.append('[');
         needComma = false;
         return this;
@@ -123,7 +126,7 @@ public class JsopBuilder {
      * @return this
      */
     public JsopBuilder key(String name) {
-        optionalComma();
+        optionalCommaAndNewline(name.length());
         if (Constants.JSON_NEWLINES) {
             buff.append('\n');
         }
@@ -170,16 +173,23 @@ public class JsopBuilder {
      * @return this
      */
     public JsopBuilder encodedValue(String value) {
-        optionalComma();
+        optionalCommaAndNewline(value.length());
         buff.append(value);
         needComma = true;
         return this;
     }
 
-    private void optionalComma() {
+    private void optionalCommaAndNewline(int add) {
         if (needComma) {
             buff.append(',');
         }
+        if (lineLength > 0) {
+            int len = buff.length();
+            if (len > lineLength / 4 && len + add - previous > lineLength) {
+                buff.append("\n ");
+                previous = len;
+            }
+        }
     }
 
     /**
@@ -276,4 +286,8 @@ public class JsopBuilder {
         }
     }
 
+    public int length() {
+        return buff.length();
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java Fri Sep  2 14:53:36 2011
@@ -22,7 +22,7 @@ package org.apache.jackrabbit.mk.json;
 public class JsopTokenizer {
 
     public static final int STRING = 0, NUMBER = 1, TRUE = 2, FALSE = 3, NULL = 4;
-    public static final int COMMENT = 5, ERROR = 6, END = 7;
+    public static final int IDENTIFIER = 5, COMMENT = 6, ERROR = 7, END = 8;
 
     private static final String[] TYPE = {
             "string", "number", "true", "false", "null", "error", "end"
@@ -175,6 +175,8 @@ public class JsopTokenizer {
             case ',':
             case '>':
             case '^':
+            case '=':
+            case ';':
                 return ch;
             case '/': {
                 ch = jsop.charAt(pos);
@@ -236,7 +238,7 @@ public class JsopTokenizer {
                 } else if (ch >= 'a' && ch <= 'z') {
                     while (pos < length) {
                         ch = jsop.charAt(pos);
-                        if (ch < 'a' || ch > 'z') {
+                        if ((ch < 'a' || ch > 'z') && (ch < '0' || ch > '9')) {
                             break;
                         }
                         pos++;
@@ -249,9 +251,8 @@ public class JsopTokenizer {
                     } else if ("false".equals(s)) {
                         return FALSE;
                     } else {
-                        // currentToken = s;
-                        // return STRING;
-                        throw getFormatException(jsop, pos);
+                        currentToken = s;
+                        return IDENTIFIER;
                     }
                 }
                 throw getFormatException(jsop, pos);
@@ -259,12 +260,29 @@ public class JsopTokenizer {
     }
 
     /**
+     * Decode a quoted Json string.
+     *
+     * @param s the encoded string, with double quotes
+     * @return the string
+     */
+    public static String decodeQuoted(String s) {
+        if (s.length() < 2 || s.charAt(0) != '\"' || s.charAt(s.length() - 1) != '\"') {
+            throw getFormatException(s, 0);
+        }
+        s = s.substring(1, s.length() - 1);
+        return decode(s);
+    }
+
+    /**
      * Decode a Json string.
      *
      * @param s the encoded string, without double quotes
      * @return the string
      */
     public static String decode(String s) {
+        if (s.indexOf('\\') < 0) {
+            return s;
+        }
         int length = s.length();
         StringBuilder buff = new StringBuilder(length);
         for (int i = 0; i < length; i++) {
@@ -386,6 +404,7 @@ public class JsopTokenizer {
             case FALSE:
             case COMMENT:
             case STRING:
+            case IDENTIFIER:
                 read();
                 break;
             default:

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java Fri Sep  2 14:53:36 2011
@@ -77,7 +77,8 @@ public class MemoryKernelImpl implements
         if (nodeMap.getRootId() == 0) {
             clear();
         } else {
-            headRevId = Revision.parseId(getRoot().getNode("head").getProperty("rev"));
+            String rev = getRoot().getNode("head").getProperty("rev");
+            headRevId = Revision.parseId(JsopTokenizer.decodeQuoted(rev));
         }
     }
 
@@ -128,20 +129,20 @@ public class MemoryKernelImpl implements
             switch (r) {
             case '+':
                 path = t.readString();
-                w.append("+ ").key(PathUtils.concat(rootPath, path));
+                w.appendTag("+ ").key(PathUtils.concat(rootPath, path));
                 t.read(':');
                 int todoSupportAddProperty;
                 t.read('{');
                 NodeImpl n = NodeImpl.parse(nodeMap, t, headRevId);
                 data = data.cloneAndAddChildNode(PathUtils.concat(fromRoot, path), false, null, n, headRevId);
                 n.append(w, -1, 0, -1, false);
-                w.appendWhitespace("\n");
+                w.newline();
                 break;
             case '-':
                 path = t.readString();
-                w.append("- ").value(PathUtils.concat(rootPath, path));
+                w.appendTag("- ").value(PathUtils.concat(rootPath, path));
                 data = data.cloneAndRemoveChildNode(PathUtils.concat(fromRoot, path), headRevId);
-                w.appendWhitespace("\n");
+                w.newline();
                 break;
             case '^':
                 path = t.readString();
@@ -149,27 +150,27 @@ public class MemoryKernelImpl implements
                 String value;
                 if (t.matches(JsopTokenizer.NULL)) {
                     value = null;
-                    w.append("^ ").key(PathUtils.concat(rootPath, path));
+                    w.appendTag("^ ").key(PathUtils.concat(rootPath, path));
                     w.value(null);
                 } else {
                     value = t.readRawValue().trim();
                     String nodeName = PathUtils.concat(fromRoot, PathUtils.getParentPath(path));
                     String propertyName = PathUtils.getName(path);
                     if (data.getNode(nodeName).hasProperty(propertyName)) {
-                        w.append("^ ").key(PathUtils.concat(rootPath, path));
+                        w.appendTag("^ ").key(PathUtils.concat(rootPath, path));
                     } else {
-                        w.append("+ ").key(PathUtils.concat(rootPath, path));
+                        w.appendTag("+ ").key(PathUtils.concat(rootPath, path));
                     }
-                    w.append(value);
+                    w.encodedValue(value);
                 }
                 data = data.cloneAndSetProperty(PathUtils.concat(fromRoot, path), value, headRevId);
-                w.appendWhitespace("\n");
+                w.newline();
                 break;
             case '>':
                 path = t.readString();
                 String from = PathUtils.concat(fromRoot, path);
                 String name = PathUtils.getName(from);
-                w.append("> ").key(PathUtils.concat(rootPath, from));
+                w.appendTag("> ").key(PathUtils.concat(rootPath, from));
                 t.read(':');
                 String position, target;
                 boolean rename;
@@ -197,7 +198,7 @@ public class MemoryKernelImpl implements
                         w.value(PathUtils.concat(rootPath, target));
                     }
                 }
-                w.appendWhitespace("\n");
+                w.newline();
                 boolean before = false;
                 if ("last".equals(position)) {
                     target = PathUtils.concat(target, name);
@@ -246,13 +247,8 @@ public class MemoryKernelImpl implements
             }
         }
         head = head.setChild("data", data, headRevId);
-        head = head.cloneAndSetProperty("rev", Revision.formatId(headRevId), headRevId);
-        head = head.cloneAndSetProperty("time", "" + clock.time(), headRevId);
-        String diff = w.toString();
-        NodeImpl commit = new NodeImpl(nodeMap, headRevId);
-        commit.setProperty("diff", diff);
-        commit.setProperty("msg", message);
-        head = head.setChild("commit", commit, headRevId);
+        Revision rev = new Revision(headRevId, clock.time(), w.toString(), message);
+        head = rev.store(head, new NodeImpl(nodeMap, headRevId));
         root = root.setChild("head", head, headRevId);
         NodeImpl old = root.getNode("old");
         if (old.getChildNodeCount() > MAX_REVISIONS_PER_NODE) {
@@ -325,15 +321,10 @@ public class MemoryKernelImpl implements
             }
         }
         Collections.sort(revisions);
-        JsopBuilder buff = new JsopBuilder().array().appendWhitespace("\n");
+        JsopBuilder buff = new JsopBuilder().array().newline();
         for (Revision rev : revisions) {
             if (rev.getId() >= fromRevId && rev.getId() <= toRevId) {
-                buff.object().
-                    key("id").value(Revision.formatId(rev.getId())).
-                    key("ts").value(rev.getTime()).
-                    key("msg").value(rev.getMsg()).
-                    key("changes").value(rev.getDiff()).
-                endObject().appendWhitespace("\n");
+                rev.appendJournal(buff);
             }
         }
         return buff.endArray().toString();

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java Fri Sep  2 14:53:36 2011
@@ -19,12 +19,8 @@ package org.apache.jackrabbit.mk.mem;
 import org.apache.jackrabbit.mk.Constants;
 import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
-import org.apache.jackrabbit.mk.util.IOUtils;
 import org.apache.jackrabbit.mk.util.PathUtils;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -115,7 +111,7 @@ public class NodeImpl {
     }
 
     private void addNode(String name, NodeImpl node) {
-        childNodes.put(name, map.addNode(node));
+        childNodes.add(name, map.addNode(node));
     }
 
     public NodeImpl cloneAndAddChildNode(String path, boolean before, String position, NodeImpl newNode, long revId) {
@@ -126,12 +122,16 @@ public class NodeImpl {
             return clone;
         }
         String child = path.substring(0, index);
+        if (childNodes == null) {
+            throw new RuntimeException("Node not found: " + path);
+        }
         NodeImpl n = getChildNode(child);
         if (n == null) {
             throw new RuntimeException("Node not found: " + path);
         }
         NodeImpl n2 = n.cloneAndAddChildNode(path.substring(index + 1), before, position, newNode, revId);
         NodeImpl c = createClone(revId);
+        c.childNodes.remove(child);
         c.addNode(child, n2);
         return c;
     }
@@ -150,6 +150,7 @@ public class NodeImpl {
         }
         NodeImpl n2 = n.cloneAndRemoveChildNode(path.substring(index + 1), revId);
         NodeImpl c = createClone(revId);
+        c.childNodes.remove(child);
         c.addNode(child, n2);
         return c;
     }
@@ -168,6 +169,7 @@ public class NodeImpl {
         }
         NodeImpl n2 = n.cloneAndSetProperty(path.substring(index + 1), value, revId);
         NodeImpl c = createClone(revId);
+        c.childNodes.remove(child);
         c.addNode(child, n2);
         return c;
     }
@@ -180,16 +182,6 @@ public class NodeImpl {
         return properties == null ? null : properties.get(propertyName);
     }
 
-    public String toString() {
-        JsopBuilder json = new JsopBuilder();
-        append(json, 0, 0, -1, false);
-        if (path != null) {
-            json.appendWhitespace("/* ").append(path).append(" */");
-        }
-        json.appendWhitespace("/* ").append("" + id).append(" */");
-        return json.toString();
-    }
-
     public void append(JsopBuilder json, int depth, long offset, int count, boolean childNodeCount) {
         json.object();
         if (properties != null) {
@@ -257,7 +249,7 @@ public class NodeImpl {
                 }
             }
             for (String m : move) {
-                childNodes.put(m, childNodes.remove(m));
+                childNodes.add(m, childNodes.remove(m));
             }
         }
     }
@@ -339,54 +331,62 @@ public class NodeImpl {
         return properties.entrySet();
     }
 
-    public static NodeImpl read(NodeMap map, InputStream in) throws IOException {
-        long revId = IOUtils.readVarLong(in);
-        NodeImpl node = new NodeImpl(map, revId);
-        node.id = map.readId(in);
-        int count = IOUtils.readVarInt(in);
-        for (int i = 0; i < count; i++) {
-            node.setProperty(IOUtils.readString(in), IOUtils.readString(in));
-        }
-        int childCount = IOUtils.readVarInt(in);
-        if (childCount < 0) {
-            childCount = -childCount;
-            int todoLargeChildNodeList;
-        } else if (childCount > 0) {
-            node.childNodes = new NodeListSmall();
-            for (int i = 0; i < childCount; i++) {
-                node.childNodes.put(IOUtils.readString(in), map.readId(in));
-            }
+    public String toString() {
+        String s = asString();
+        if (path != null) {
+            s += "/* " + path + " */";
         }
-        return node;
+        return s;
     }
 
-    public void write(OutputStream out) throws IOException {
-        IOUtils.writeVarLong(out, revId);
-        map.writeId(out, map.getId(id));
-        if (properties == null) {
-            IOUtils.writeVarInt(out, 0);
-        } else {
-            IOUtils.writeVarInt(out, properties.size());
+    public String asString() {
+        JsopBuilder json = new JsopBuilder();
+        json.setLineLength(80);
+        json.encodedValue(map.formatId(id)).appendTag("=");
+        json.object();
+        if (properties != null && properties.size() > 0) {
             for (Entry<String, String> e : properties.entrySet()) {
-                IOUtils.writeString(out, e.getKey());
-                IOUtils.writeString(out, e.getValue());
+                json.key(e.getKey()).encodedValue(e.getValue());
             }
         }
-        if (childNodes == null) {
-            IOUtils.writeVarInt(out, 0);
-        } else {
-            IOUtils.writeVarLong(out, childNodes.size());
+        if (childNodes != null && childNodes.size() > 0) {
             for (Iterator<String> it = childNodes.getNames(0); it.hasNext();) {
                 String n = it.next();
-                IOUtils.writeString(out, n);
+                json.key(n);
                 long x = childNodes.get(n);
                 long y = map.getId(x);
                 if (x != y) {
-                    childNodes.put(n, y);
+                    childNodes.setId(n, y);
                 }
-                map.writeId(out, y);
+                json.encodedValue(map.formatId(y));
             }
         }
+        return json.endObject().toString();
+    }
+
+    public static NodeImpl fromString(NodeMap map, String s) {
+        JsopTokenizer t = new JsopTokenizer(s);
+        NodeImpl node = new NodeImpl(map, 0);
+        node.id = map.parseId(t.readRawValue());
+        t.read('=');
+        t.read('{');
+        if (!t.matches('}')) {
+            do {
+                String key = t.readString();
+                t.read(':');
+                String value = t.readRawValue();
+                if (value.length() > 0 && value.charAt(0) >= 'a') {
+                    if (node.childNodes == null) {
+                        node.childNodes = new NodeListSmall();
+                    }
+                    node.childNodes.add(key, map.parseId(value));
+                } else {
+                    node.setProperty(key, value);
+                }
+            } while (t.matches(','));
+            t.read('}');
+        }
+        return node;
     }
 
     NodeList getNodeList() {
@@ -405,4 +405,14 @@ public class NodeImpl {
         return result.cloneAndAddChildNode(name, false, null, child, revId);
     }
 
+    void visit(ChildVisitor v) {
+        if (childNodes != null) {
+            childNodes.visit(v);
+        }
+    }
+
+    interface ChildVisitor {
+        void accept(long childId);
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeList.java Fri Sep  2 14:53:36 2011
@@ -1,6 +1,7 @@
 package org.apache.jackrabbit.mk.mem;
 
 import java.util.Iterator;
+import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
 
 interface NodeList {
 
@@ -10,7 +11,9 @@ interface NodeList {
 
     Long get(String name);
 
-    void put(String name, Long x);
+    void add(String name, Long x);
+
+    void setId(String name, Long x);
 
     Iterator<String> getNames(long offset);
 
@@ -18,4 +21,6 @@ interface NodeList {
 
     NodeList createClone(NodeMap map);
 
+    void visit(ChildVisitor v);
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListLarge.java Fri Sep  2 14:53:36 2011
@@ -19,9 +19,13 @@ package org.apache.jackrabbit.mk.mem;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
 
 public class NodeListLarge implements NodeList {
 
+    private static final int BLOOM_FILTER_SIZE = 256;
+
     ArrayList<Child> children;
     private final NodeMap map;
     private long size;
@@ -31,6 +35,17 @@ public class NodeListLarge implements No
         children = new ArrayList<Child>();
     }
 
+    public NodeListLarge(NodeMap map, LinkedHashMap<String, Long> list) {
+        this.map = map;
+        NodeImpl childNode = new NodeImpl(map, 0);
+        long id = map.addNode(childNode);
+        Child c = new Child();
+        c.id = id;
+        children = new ArrayList<Child>();
+        children.add(c);
+        // TODO Auto-generated constructor stub
+    }
+
     public boolean containsKey(String name) {
         for (Child c : children) {
             if (c.possiblyContains(name)) {
@@ -40,6 +55,10 @@ public class NodeListLarge implements No
         return false;
     }
 
+    public void setId(String name, Long x) {
+        int todoKeepOrder;
+    }
+
     NodeList getList(Child c) {
         NodeImpl n = map.getNode(c.id);
         return n.getNodeList();
@@ -105,23 +124,10 @@ public class NodeListLarge implements No
         return it;
     }
 
-    public void put(String name, Long x) {
-        for (Child c : children) {
-            if (c.possiblyContains(name)) {
-                NodeList child = getList(c);
-                if (child.containsKey(name)) {
-                    Long y = child.remove(name);
-                    if (y == null) {
-                        throw new RuntimeException("Could not remove " + name);
-                    }
-                    size--;
-                    break;
-                }
-            }
-        }
+    public void add(String name, Long x) {
         Child c = children.get(children.size() - 1);
         NodeList child = getList(c);
-        child.put(name, x);
+        child.add(name, x);
         size++;
     }
 
@@ -147,10 +153,11 @@ public class NodeListLarge implements No
     }
 
     static class Child {
-        static final int BLOOM_FILTER_SIZE = 256;
+        NodeMap map;
+        long id;
+
         BitSet nameBloomFilter = new BitSet(BLOOM_FILTER_SIZE);
         long size;
-        long id;
         boolean possiblyContains(String name) {
             return nameBloomFilter.get(name.hashCode() & (BLOOM_FILTER_SIZE - 1));
         }
@@ -164,7 +171,7 @@ public class NodeListLarge implements No
             NodeListSmall s = new NodeListSmall();
             for (Iterator<String> it = getNames(0); it.hasNext();) {
                 String n = it.next();
-                s.put(n, get(n));
+                s.add(n, get(n));
             }
             return s;
         }
@@ -172,4 +179,10 @@ public class NodeListLarge implements No
         return new NodeListLarge(map, children);
     }
 
+    public void visit(ChildVisitor v) {
+        for (Child c : children) {
+            v.accept(c.id);
+        }
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeListSmall.java Fri Sep  2 14:53:36 2011
@@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
 import java.util.Map.Entry;
 import org.apache.jackrabbit.mk.json.JsopBuilder;
 import org.apache.jackrabbit.mk.json.JsopTokenizer;
+import org.apache.jackrabbit.mk.mem.NodeImpl.ChildVisitor;
 
 public class NodeListSmall implements NodeList {
 
@@ -46,7 +47,15 @@ public class NodeListSmall implements No
         return list.get(name);
     }
 
-    public void put(String name, Long x) {
+    public void add(String name, Long x) {
+        Long old = list.put(name, x);
+        if (old != null) {
+            throw new RuntimeException("Node already exists: " + name);
+        }
+    }
+
+    public void setId(String name, Long x) {
+        int todoKeepOrder;
         list.put(name, x);
     }
 
@@ -97,9 +106,15 @@ public class NodeListSmall implements No
 
     public NodeList createClone(NodeMap map) {
         if (list.size() > map.getMaxMemoryChildren()) {
-
+            return new NodeListLarge(map, list);
         }
         return new NodeListSmall(new LinkedHashMap<String, Long>(list));
     }
 
+    public void visit(ChildVisitor v) {
+        for (Long c : list.values()) {
+            v.accept(c);
+        }
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeMap.java Fri Sep  2 14:53:36 2011
@@ -24,9 +24,12 @@ import org.apache.jackrabbit.mk.util.IOU
 
 public class NodeMap {
 
+    private static final int MAX_MEMORY_CHILDREN = Integer.MAX_VALUE;
+
     private HashMap<Long, NodeImpl> nodes = new HashMap<Long, NodeImpl>();
     private long nextId = 1;
     private long rootId;
+    private int maxMemoryChildren = MAX_MEMORY_CHILDREN;
 
     public long addNode(NodeImpl node) {
         long x = node.getId();
@@ -47,9 +50,12 @@ public class NodeMap {
         nextId = 1;
     }
 
+    public void setMaxMemoryChildren(int max) {
+        maxMemoryChildren = max;
+    }
+
     public int getMaxMemoryChildren() {
-        int todoTestOtherValues;
-        return 20;
+        return maxMemoryChildren;
     }
 
     public void close() {
@@ -77,4 +83,12 @@ public class NodeMap {
         return rootId;
     }
 
+    public String formatId(long id) {
+        return "n" + id;
+    }
+
+    public long parseId(String id) {
+        return Long.parseLong(id.substring(1));
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/Revision.java Fri Sep  2 14:53:36 2011
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.mk.mem;
 
 import org.apache.jackrabbit.mk.json.JsopBuilder;
+import org.apache.jackrabbit.mk.json.JsopTokenizer;
 
 /**
  * A revision, including pointer to the root node of that revision.
@@ -32,7 +33,8 @@ public class Revision implements Compara
     Revision(NodeImpl node) {
         this.node = node;
         if (node.hasProperty("rev")) {
-            id = parseId(node.getProperty("rev"));
+            String r = node.getProperty("rev");
+            id = parseId(r.substring(1, r.length() - 1));
             time = Long.parseLong(node.getProperty("time"));
         } else {
             id = time = 0;
@@ -70,10 +72,12 @@ public class Revision implements Compara
 
     private String getCommitValue(String s) {
         if (node.exists("commit")) {
-            return node.getNode("commit").getProperty(s);
-        } else {
-            return "";
+            String v = node.getNode("commit").getProperty(s);
+            if (v != null) {
+                return JsopTokenizer.decodeQuoted(v);
+            }
         }
+        return "";
     }
 
     public int compareTo(Revision o) {
@@ -95,4 +99,23 @@ public class Revision implements Compara
         return Long.toHexString(revId);
     }
 
+    NodeImpl store(NodeImpl head, NodeImpl commit) {
+        head = head.cloneAndSetProperty("rev", JsopBuilder.encode(formatId(id)), id);
+        head = head.cloneAndSetProperty("time", "" + time, id);
+        commit.setProperty("diff", JsopBuilder.encode(diff));
+        if (msg != null) {
+            commit.setProperty("msg", JsopBuilder.encode(msg));
+        }
+        return head.setChild("commit", commit, id);
+    }
+
+    public void appendJournal(JsopBuilder buff) {
+        buff.object().
+            key("id").value(Revision.formatId(id)).
+            key("ts").value(time).
+            key("msg").value(getMsg()).
+            key("changes").value(getDiff()).
+        endObject().newline();
+    }
+
 }

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java Fri Sep  2 14:53:36 2011
@@ -204,7 +204,7 @@ public class DbBlobStoreTest extends Tes
             in.close();
             String name = f.substring(parent.length());
             listing.key(name).value(id);
-            listing.appendWhitespace("\n");
+            listing.newline();
         }
         listing.endObject();
         String l = listing.toString();

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java Fri Sep  2 14:53:36 2011
@@ -51,6 +51,19 @@ public class JsopTest extends TestCase {
         assertEquals(null, t.read(JsopTokenizer.NULL));
     }
 
+    public void testLineLength() {
+        JsopBuilder buff = new JsopBuilder();
+        buff.key("hello").value("world");
+        assertEquals("\"hello\":\"world\"", buff.toString());
+        assertEquals(15, buff.length());
+        buff = new JsopBuilder();
+
+        buff.setLineLength(10);
+        buff.key("hello").value("world");
+        assertEquals("\"hello\":\n \"world\"", buff.toString());
+        assertEquals(17, buff.length());
+    }
+
     public void testNumber() {
         JsopTokenizer t = new JsopTokenizer("9/3:-3-:-/- 3");
         assertEquals("9", t.read(JsopTokenizer.NUMBER));
@@ -108,11 +121,11 @@ public class JsopTest extends TestCase {
         test("/error/", "\"\\");
         test("/error/1", ".1");
         assertEquals("x", new JsopTokenizer("x").toString());
-        test("/error/", "true" + "true");
-        test("/error/", "truer");
-        test("/error/", "falsehood");
-        test("/error/", "nil");
-        test("/error/1", "nil 1");
+        test("/id:truetrue/", "true" + "true");
+        test("/id:truer/", "truer");
+        test("/id:falsehood/", "falsehood");
+        test("/id:nil/", "nil");
+        test("/id:nil/1", "nil 1");
         test("/error/", "\"invalid");
         test("- \"test/test\"", "-\"test\\/test\"");
         test(" {\n\"x\": 1,\n\"y\": 2\n}\n", "{\"x\":1, \"y\":2}");
@@ -131,7 +144,7 @@ public class JsopTest extends TestCase {
         test(" {\n\"a\": /* test */ 10\n}\n", "{ \"a\": /* test */ 10}");
         test("+ - / ^ ", "+ - / ^");
         test("/*/ comment /*/ ", "/*/ comment /*/");
-        test("/**/ /error//**/ ", "/**/ comment /**/");
+        test("/**/ /id:comment//**/ ", "/**/ comment /**/");
 
         JsopTokenizer t = new JsopTokenizer("{}123");
         assertFalse(t.matches('+'));
@@ -194,6 +207,9 @@ public class JsopTest extends TestCase {
                 case JsopTokenizer.ERROR:
                     buff.append("/error/");
                     break;
+                case JsopTokenizer.IDENTIFIER:
+                    buff.append("/id:").append(t.getToken()).append('/');
+                    break;
                 case JsopTokenizer.COMMENT:
                     buff.append("/*").append(t.getToken()).append("*/ ");
                     break;
@@ -243,7 +259,7 @@ public class JsopTest extends TestCase {
     public void testBuilder() throws IOException {
 
         JsopBuilder buff = new JsopBuilder();
-        buff.append("+ ").object().
+        buff.appendTag("+ ").object().
                 key("foo").value("bar").
                 key("int").value(3).
                 key("decimal").encodedValue("3.0").
@@ -270,24 +286,18 @@ public class JsopTest extends TestCase {
 
         buff.reset();
         buff.array().
-                object().key("x").value("1").endObject().appendWhitespace("\n").
-                object().key("y").value("2").endObject().appendWhitespace("\n").
+                object().key("x").value("1").endObject().newline().
+                object().key("y").value("2").endObject().newline().
                 endArray();
         json = buff.toString();
         assertEquals("[{\"x\":\"1\"}\n,{\"y\":\"2\"}\n]", json);
 
         buff = new JsopBuilder();
-        buff.append("+ ").key("x").value("1").appendWhitespace("\n");
-        buff.append("+ ").key("y").value("2").appendWhitespace("\n");
+        buff.appendTag("+ ").key("x").value("1").newline();
+        buff.appendTag("+ ").key("y").value("2").newline();
         json = buff.toString();
         assertEquals("+ \"x\":\"1\"\n+ \"y\":\"2\"\n", json);
 
-        buff = new JsopBuilder();
-        buff.appendWhitespace("+ ").key("x").value("1").appendWhitespace("\n");
-        buff.appendWhitespace("+ ").key("y").value("2").appendWhitespace("\n");
-        json = buff.toString();
-        assertEquals("+ \"x\":\"1\"\n+ ,\"y\":\"2\"\n", json);
-
     }
 
     public void testEscape() throws IOException {

Modified: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java?rev=1164559&r1=1164558&r2=1164559&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java (original)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/large/LargeNodeTest.java Fri Sep  2 14:53:36 2011
@@ -19,6 +19,8 @@ package org.apache.jackrabbit.mk.large;
 import junit.framework.TestCase;
 import org.apache.jackrabbit.mk.MicroKernelFactory;
 import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.mem.NodeImpl;
+import org.apache.jackrabbit.mk.mem.NodeMap;
 
 /**
  * Test moving nodes.
@@ -64,4 +66,37 @@ public class LargeNodeTest extends TestC
         return s;
     }
 
+    public void testAddChildNodes() {
+        NodeMap map = new NodeMap();
+
+        map.setMaxMemoryChildren(2);
+
+        NodeImpl n = new NodeImpl(map, 0);
+        assertEquals("n0={}", n.asString());
+        n.setId(255);
+        assertEquals("n255={}", n.asString());
+        n.setPath("/test");
+        assertEquals("n255={}/* /test */", n.toString());
+        n = n.createClone(10);
+        assertEquals("n0={}", n.asString());
+        NodeImpl a = new NodeImpl(map, 0);
+        NodeImpl b = new NodeImpl(map, 0);
+        NodeImpl c = new NodeImpl(map, 0);
+        n = n.cloneAndAddChildNode("a", false, null, a, 11);
+        n = n.cloneAndSetProperty("x", "1", 12);
+        n.setId(3);
+        assertEquals("n3={\"x\":1,\"a\":n1}", n.asString());
+        NodeImpl n2 = NodeImpl.fromString(map, n.asString());
+        assertEquals("n3={\"x\":1,\"a\":n1}", n2.asString());
+
+        n = new NodeImpl(map, 0);
+        n = n.cloneAndAddChildNode("a", false, null, a, 1);
+        assertEquals("n0={\"a\":n1}", n.asString());
+        n = n.cloneAndAddChildNode("b", false, null, b, 1);
+        assertEquals("n0={\"a\":n1,\"b\":n2}", n.asString());
+        n = n.cloneAndAddChildNode("c", false, null, c, 1);
+        assertEquals("n0={\"a\":n1,\"b\":n2,\"c\":n3}", n.asString());
+
+    }
+
 }
\ No newline at end of file