You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by md...@apache.org on 2011/12/08 19:18:45 UTC

svn commit: r1212018 [3/7] - in /jackrabbit/sandbox/jackrabbit-microkernel: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/jackrabbit/ src/main/java/org/apache/jackrabbit/configuration/ src/main/j...

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,199 @@
+/*
+ * 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.json;
+
+import org.apache.jackrabbit.json.Token.Type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * DIFFS     ::= DIFF*
+ * DIFF      ::= ADD | SET | REMOVE | MOVE | TEST | METADATA | EXTENSION
+ * ADD       ::= + STRING : (OBJECT | ATOM | ARRAY)
+ * SET       ::= ^ STRING : ATOM | ARRAY
+ * REMOVE    ::= - STRING
+ * MOVE      ::= > STRING : (STRING | { STRING : STRING })
+ * TEST      ::= = STRING : ATOM | ARRAY
+ * METADATA  ::= @ OBJECT
+ * EXTENSION ::= OP STRING ":" (OBJECT | ATOM | ARRAY)
+ */
+public class JsopParser {
+    private final JsopHandler jsopHandler;
+
+    public JsopParser(JsopHandler jsopHandler) {
+        this.jsopHandler = jsopHandler;
+    }
+
+    /* DIFFS    ::= DIFF* */
+    public void parseJsop(JsonTokenizer tokenizer) {
+        for (Token token = tokenizer.peek(); token.type() != Type.EOF; token = tokenizer.peek()) {
+            parseDiff(tokenizer);
+        }
+    }
+
+    /* DIFF    ::= ADD | SET | REMOVE | MOVE */
+    public void parseDiff(JsonTokenizer tokenizer) {
+        Token token = tokenizer.read(Type.UNKNOWN);
+        String text = token.text();
+        if (text.length() != 1) {
+            throw new ParseException(token.pos(), "Expected one of +, -, ^ or >. Found: " + token);
+        }
+
+        switch (text.charAt(0)) {
+            case '+':
+                parseAdd(tokenizer);
+                break;
+            case '-':
+                parseRemove(tokenizer);
+                break;
+            case '^':
+                parseSet(tokenizer);
+                break;
+            case '>':
+                parseMove(tokenizer);
+                break;
+            case '=':
+                parseTest(tokenizer);
+                break;
+            case '@':
+                parseMetadata(tokenizer);
+                break;
+            default:
+                parseExtension(text.charAt(0), tokenizer);
+        }
+    }
+
+    /* ADD      ::= + STRING : (OBJECT | ATOM | ARRAY) */
+    public void parseAdd(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        switch (tokenizer.peek().type()) {
+            case BEGIN_OBJECT:
+                jsopHandler.add(path, tokenizer);
+                break;
+            case BEGIN_ARRAY:
+                jsopHandler.add(path, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.add(path, parseAtom(tokenizer));
+        }
+    }
+
+    /* REMOVE   ::= - STRING */
+    public void parseRemove(JsonTokenizer tokenizer) {
+        jsopHandler.remove(tokenizer.read(Type.STRING));
+    }
+
+    /* SET      ::= ^ STRING : ATOM | ARRAY*/
+    public void parseSet(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        Token token = tokenizer.peek();
+        switch (token.type()) {
+            case BEGIN_OBJECT:
+                throw new ParseException(token.pos(), "Expected one of atom or array. Found: " + token);
+            case BEGIN_ARRAY:
+                jsopHandler.set(path, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.set(path, parseAtom(tokenizer));
+        }
+    }
+
+    /* MOVE     ::= > STRING : (STRING | { STRING : STRING }) */
+    public void parseMove(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        if (tokenizer.peek(Type.BEGIN_OBJECT)) {
+            tokenizer.read(Type.BEGIN_OBJECT);
+            Token position = tokenizer.read(Type.STRING);
+            tokenizer.read(Type.COLON);
+            Token target = tokenizer.read(Type.STRING);
+            tokenizer.read(Type.END_OBJECT);
+            jsopHandler.reorder(path, position, target);
+        }
+        else {
+            jsopHandler.move(path, tokenizer.read(Type.STRING));
+        }
+    }
+
+    /* TEST     ::= = STRING : ATOM | ARRAY */
+    public void parseTest(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        Token token = tokenizer.peek();
+        switch (token.type()) {
+            case BEGIN_OBJECT:
+                throw new ParseException(token.pos(), "Expected one of atom or array. Found: " + token);
+            case BEGIN_ARRAY:
+                jsopHandler.test(path, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.test(path, parseAtom(tokenizer));
+        }
+    }
+
+    /* METADATA ::= @ OBJECT */
+    public void parseMetadata(JsonTokenizer tokenizer) {
+        jsopHandler.metaData(tokenizer);
+    }
+
+    /* EXTENSION ::= OP STRING ":" (OBJECT | ATOM | ARRAY) */
+    public void parseExtension(char op, JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        switch (tokenizer.peek().type()) {
+            case BEGIN_OBJECT:
+                jsopHandler.extension(op, path, tokenizer);
+                break;
+            case BEGIN_ARRAY:
+                jsopHandler.extension(op, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.extension(op, parseAtom(tokenizer));
+        }
+    }
+
+    //------------------------------------------< private >---
+
+    private static Token parseAtom(JsonTokenizer tokenizer) {
+        Token token = tokenizer.peek();
+        Type type = token.type();
+        if (type != Type.TRUE && type != Type.FALSE && type != Type.NULL && type != Type.STRING && type != Type.NUMBER) {
+            throw new ParseException(token.pos(), "Expected one of atom. Found: " + token);
+        }
+        return tokenizer.read();
+    }
+
+    private static Token[] parseArray(JsonTokenizer tokenizer) {
+        final List<Token> values = new ArrayList<Token>();
+        
+        new JsonParser(new JsonHandler(){
+            @Override
+            public void atom(Token key, Token value) {
+                values.add(value);
+            }
+        }).parseArray(tokenizer);
+        
+        return values.toArray(new Token[values.size()]);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java.orig
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java.orig?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java.orig (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/JsopParser.java.orig Thu Dec  8 18:18:42 2011
@@ -0,0 +1,155 @@
+/*
+ * 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 michid.jcr.json;
+
+import michid.jcr.json.Token.Type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * DIFFS    ::= DIFF*
+ * DIFF     ::= ADD | SET | REMOVE | MOVE
+ * ADD      ::= + STRING : (OBJECT | ATOM | ARRAY)
+ * SET      ::= ^ STRING : ATOM | ARRAY
+ * REMOVE   ::= - STRING
+ * MOVE     ::= > STRING : (STRING | { STRING : STRING })
+ */
+public class JsopParser {
+    private final JsopHandler jsopHandler;
+
+    public JsopParser(JsopHandler jsopHandler) {
+        this.jsopHandler = jsopHandler;
+    }
+
+    /* DIFFS    ::= DIFF* */
+    public void parseJsop(JsonTokenizer tokenizer) {
+        for (Token token = tokenizer.peek(); token.type() != Type.EOF; token = tokenizer.peek()) {
+            parseDiff(tokenizer);
+        }
+    }
+
+    /* DIFF    ::= ADD | SET | REMOVE | MOVE */
+    public void parseDiff(JsonTokenizer tokenizer) {
+        Token token = tokenizer.read(Type.UNKNOWN);
+        String text = token.text();
+        if (text.length() != 1) {
+            throw new ParseException(token.pos(), "Expected one of +, -, ^ or >. Found: " + token);
+        }
+
+        switch (text.charAt(0)) {
+            case '+':
+                parseAdd(tokenizer);
+                break;
+            case '-':
+                parseRemove(tokenizer);
+                break;
+            case '^':
+                parseSet(tokenizer);
+                break;
+            case '>':
+                parseMove(tokenizer);
+                break;
+            default:
+                throw new ParseException(token.pos(), "Expected one of +, -, ^ or >. Found: " + token);
+        }
+    }
+
+    /* ADD      ::= + STRING : (OBJECT | ATOM | ARRAY) */
+    public void parseAdd(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        switch (tokenizer.peek().type()) {
+            case BEGIN_OBJECT:
+                jsopHandler.add(path, tokenizer);
+                break;
+            case BEGIN_ARRAY:
+                jsopHandler.add(path, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.add(path, parseAtom(tokenizer));
+        }
+    }
+
+    /* REMOVE   ::= - STRING */
+    public void parseRemove(JsonTokenizer tokenizer) {
+        jsopHandler.remove(tokenizer.read(Type.STRING));
+    }
+
+    /* SET      ::= ^ STRING : ATOM | ARRAY*/
+    public void parseSet(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        Token token = tokenizer.peek();
+        switch (token.type()) {
+            case BEGIN_OBJECT:
+                throw new ParseException(token.pos(), "Expected one of atom or array. Found: " + token);
+            case BEGIN_ARRAY:
+                jsopHandler.set(path, parseArray(tokenizer));
+                break;
+            default:
+                jsopHandler.set(path, parseAtom(tokenizer));
+        }
+        if (tokenizer.peek(Type.BEGIN_OBJECT)) {
+        }
+    }
+
+    /* MOVE     ::= > STRING : (STRING | { STRING : STRING }) */
+    public void parseMove(JsonTokenizer tokenizer) {
+        Token path = tokenizer.read(Type.STRING);
+        tokenizer.read(Type.COLON);
+        if (tokenizer.peek(Type.BEGIN_OBJECT)) {
+            tokenizer.read(Type.BEGIN_OBJECT);
+            Token position = tokenizer.read(Type.STRING);
+            tokenizer.read(Type.COLON);
+            Token target = tokenizer.read(Type.STRING);
+            tokenizer.read(Type.END_OBJECT);
+            jsopHandler.reorder(path, position, target);
+        }
+        else {
+            jsopHandler.move(path, tokenizer.read(Type.STRING));
+        }
+    }
+
+    //------------------------------------------< private >---
+
+    private static Token parseAtom(JsonTokenizer tokenizer) {
+        Token token = tokenizer.peek();
+        Type type = token.type();
+        if (type != Type.TRUE && type != Type.FALSE && type != Type.NULL && type != Type.STRING && type != Type.NUMBER) {
+            throw new ParseException(token.pos(), "Expected one of atom. Found: " + token);
+        }
+        return tokenizer.read();
+    }
+
+    private static Token[] parseArray(JsonTokenizer tokenizer) {
+        final List<Token> values = new ArrayList<Token>();
+        
+        new JsonParser(new JsonHandler(){
+            @Override
+            public void atom(Token key, Token value) {
+                values.add(value);
+            }
+        }).parseArray(tokenizer);
+        
+        return values.toArray(new Token[values.size()]);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,193 @@
+/*
+ * 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.json;
+
+import org.apache.jackrabbit.json.JsonValue.JsonArray;
+import org.apache.jackrabbit.json.JsonValue.JsonAtom;
+import org.apache.jackrabbit.json.JsonValue.JsonObject;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Utility class for parsing JSON objects and arrays into {@link JsonObject}s
+ * and {@link JsonArray}s, respectively. In contrast to {@link FullJsonParser},
+ * this implementation resolves nested structures lazily. That, is it does a
+ * level order traverse of the JSON tree.
+ * <p/>
+ * The parser looks for 'hints' in the JSON text to speed up parsing: when it
+ * encounters an integer value with the key ":size" in an object, that value
+ * is used for the size of the entire object (including sub-objects).
+ *
+ * @see FullJsonParser
+ */
+public final class LevelOrderJsonParser {
+    private LevelOrderJsonParser() { }
+    
+    /**
+     * Parse a JSON object from {@code tokenizer}
+     * @param tokenizer
+     * @return a {@code JsonObject}
+     * @throws ParseException
+     */
+    public static JsonObject parseObject(JsonTokenizer tokenizer) {
+        ObjectHandler objectHandler = new ObjectHandler();
+        new JsonParser(objectHandler).parseObject(tokenizer);
+        return objectHandler.getObject();
+    }
+
+    /**
+     * Parse a JSON array from {@code tokenizer}
+     * @param tokenizer
+     * @return a {@code JsonArray}
+     * @throws ParseException
+     */
+    public static JsonArray parseArray(JsonTokenizer tokenizer) {
+        ArrayHandler arrayHandler = new ArrayHandler();
+        new JsonParser(arrayHandler).parseArray(tokenizer);
+        return arrayHandler.getArray();
+    }
+
+    /**
+     * This implementation of a {@code JsonHandler} builds up a {@code JsonObject}
+     * from its constituents. Nested objects are not fully parsed though, but a
+     * reference to the parser is kept which is only invoked when that nested object
+     * is actually accessed.
+     */
+    public static class ObjectHandler extends JsonHandler {
+        private final JsonObject object = new JsonObject(new LinkedHashMap<String, JsonValue>());
+
+        @Override
+        public void atom(Token key, Token value) {
+            object.put(key.text(), new JsonAtom(value));
+        }
+
+        @Override
+        public void object(JsonParser parser, Token key, JsonTokenizer tokenizer) {
+            object.put(key.text(), new DeferredObjectValue(tokenizer.copy()));
+            tokenizer.setPos(getNextPairPos(tokenizer.copy()));
+        }
+
+        @Override
+        public void array(JsonParser parser, Token key, JsonTokenizer tokenizer) {
+            object.put(key.text(), parseArray(tokenizer));
+        }
+
+        public JsonObject getObject() {
+            return object;
+        }
+
+    }
+
+    /**
+     * This implementation of a {@code JsonHandler} builds up a {@code JsonArray}
+     * from its constituents. Nested objects are not fully parsed though, but a
+     * reference to the parser is kept which is only invoked when that nested object
+     * is actually accessed.
+     */
+    public static class ArrayHandler extends JsonHandler {
+        private final JsonArray array = new JsonArray(new ArrayList<JsonValue>());
+
+        @Override
+        public void atom(Token key, Token value) {
+            array.add(new JsonAtom(value));
+        }
+
+        @Override
+        public void object(JsonParser parser, Token key, JsonTokenizer tokenizer) {
+            array.add(new DeferredObjectValue(tokenizer.copy()));
+            tokenizer.setPos(getNextPairPos(tokenizer.copy()));
+        }
+
+        @Override
+        public void array(JsonParser parser, Token key, JsonTokenizer tokenizer) {
+            array.add(parseArray(tokenizer));
+        }
+
+        public JsonArray getArray() {
+            return array;
+        }
+    }
+
+    //------------------------------------------< private >---
+
+    private static class BreakException extends RuntimeException{
+        private static final BreakException BREAK = new BreakException();
+    }
+
+    private static int getNextPairPos(JsonTokenizer tokenizer) {
+        SkipObjectHandler skipObjectHandler = new SkipObjectHandler(tokenizer.pos());
+        try {
+            new JsonParser(skipObjectHandler).parseObject(tokenizer);
+        }
+        catch (BreakException e) {
+            return skipObjectHandler.newPos;
+        }
+        return tokenizer.pos();
+    }
+
+    private static class DeferredObjectValue extends JsonObject {
+        private final JsonTokenizer tokenizer;
+
+        public DeferredObjectValue(JsonTokenizer tokenizer) {
+            super(null);
+            this.tokenizer = tokenizer;
+        }
+
+        @Override
+        public void put(String key, JsonValue value) {
+            throw new IllegalStateException("Cannot add value");
+        }
+
+        @Override
+        public JsonValue get(String key) {
+            return value().get(key);
+        }
+
+        @Override
+        public Map<String, JsonValue> value() {
+            return parseObject(tokenizer.copy()).value();
+        }
+
+        @Override
+        public String toString() {
+            return "<deferred>";
+        }
+
+    }
+
+    private static class SkipObjectHandler extends JsonHandler {
+        private final int startPos;
+        private int newPos;
+
+        public SkipObjectHandler(int startPos) {
+            this.startPos = startPos;
+        }
+
+        @Override
+        public void atom(Token key, Token value) {
+            if (key != null && ":size".equals(key.text()) && Token.Type.NUMBER == value.type()) {
+                newPos = startPos + Integer.parseInt(value.text());
+                throw BreakException.BREAK;
+            }
+        }
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/LevelOrderJsonParser.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,34 @@
+/*
+ * 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.json;
+
+/**
+ * This exception is thrown when a lexical or a syntax error occurs
+ * while parsing a JSON document. 
+ */
+public class ParseException extends RuntimeException {
+    public ParseException(int pos, String message) {
+        super(pos + ": " + message);
+    }
+
+    public ParseException(int pos, String message, Throwable cause) {
+        super(pos + ": " + message, cause);
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/ParseException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,79 @@
+/*
+ * 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.json;
+
+/**
+ * A token represents the smallest lexical unit in a JSON document.
+ * A token has a {@link Type type}, a {@link #text() text} and a
+ * {@link #pos() position} which refers to its place in the originating
+ * JSON document. Note that the position is <em>not</em> taken into account
+ * for equality.
+ */
+public final class Token {
+    private final Type type;
+    private final String text;
+    private final int pos;
+
+    public enum Type {BEGIN_OBJECT, END_OBJECT, BEGIN_ARRAY, END_ARRAY, COLON, COMMA, EOF, TRUE,
+        FALSE, NULL, STRING, NUMBER, UNKNOWN}
+
+    public Token(Type type, String text, int pos) {
+        this.type = type;
+        this.text = text;
+        this.pos = pos;
+    }
+
+    public Type type() {
+        return type;
+    }
+
+    public String text() {
+        return text;
+    }
+
+    public int pos() {
+        return pos;
+    }
+
+    @Override
+    public String toString() {
+        return "Token[" + type + ", " + text + ", " + pos + ']';
+    }
+
+    @Override
+    public int hashCode() {
+        return 37 * (37 * (17 + type().hashCode()) + text().hashCode());
+    }
+
+    /**
+     * Two tokens are equal if and only if their texts and their types
+     * are equal.
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof Token) {
+            Token that = (Token) other;
+            return that.type == type && that.text.equals(text);
+        }
+        else {
+            return false;
+        }
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/Token.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,67 @@
+/*
+ * 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.json;
+
+import org.apache.jackrabbit.json.Token.Type;
+
+/**
+ * This JSON tokenizer operates on a string as its input. In contrast to
+ * {@link DefaultJsonTokenizer} it <em>does</em> unescape JSON string values.
+ */
+public class UnescapingJsonTokenizer extends DefaultJsonTokenizer {
+    public UnescapingJsonTokenizer(String json) {
+        super(json);
+    }
+
+    /**
+     * @see JsonTokenizer#JsonTokenizer(JsonTokenizer)
+     */
+    protected UnescapingJsonTokenizer(UnescapingJsonTokenizer tokenizer) {
+        super(tokenizer);    
+    }
+
+    @Override
+    public UnescapingJsonTokenizer copy() {
+        return new UnescapingJsonTokenizer(this);
+    }
+
+    //------------------------------------------< protected >---
+
+    @Override
+    protected Token createToken(Type type, String text, int pos) {
+        return super.createToken(type, type == Type.STRING ? unescape(text) : text, pos);
+    }
+
+    //------------------------------------------< private >---
+    
+    private String unescape(String text) {
+        try {
+            return JsonValue.unescape(text);
+        }
+        catch (IndexOutOfBoundsException e) {
+            throw new ParseException(pos(), "Invalid character escaping in string", e);
+        }
+        catch (NumberFormatException e) {
+            throw new ParseException(pos(), "Invalid character escaping in string", e);
+        }
+    }
+
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/json/UnescapingJsonTokenizer.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,27 @@
+/*
+ * 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.security;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+
+public interface Authenticator {
+    CredentialsInfo authenticate(Credentials credentials) throws LoginException;
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/Authenticator.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,100 @@
+/*
+ * 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.security;
+
+
+import javax.jcr.Credentials;
+import javax.jcr.GuestCredentials;
+import javax.jcr.LoginException;
+import javax.jcr.SimpleCredentials;
+
+import java.util.Arrays;
+
+import static java.text.MessageFormat.format;
+
+public class AuthenticatorImpl implements Authenticator {
+    public static final Authenticator INSTANCE = new AuthenticatorImpl();
+
+    private AuthenticatorImpl() {}
+
+    @Override
+    public CredentialsInfo authenticate(Credentials credentials) throws LoginException {
+        // todo implement authentication, split into aggregate of SimpleAuthenticator, GuestAuthenticator, etc
+        if (credentials == null) {
+            return new CredentialsInfo() {
+                @Override
+                public String getUserId() {
+                    return "null";
+                }
+
+                @Override
+                public String[] getAttributeNames() {
+                    return new String[0];
+                }
+
+                @Override
+                public Object getAttribute(String name) {
+                    return null;
+                }
+            };
+        }
+        else if (credentials instanceof SimpleCredentials) {
+            final SimpleCredentials c = ((SimpleCredentials) credentials);
+            Arrays.fill(c.getPassword(), '\0');
+            return new CredentialsInfo() {
+                @Override
+                public String getUserId() {
+                    return c.getUserID();
+                }
+
+                @Override
+                public String[] getAttributeNames() {
+                    return c.getAttributeNames();
+                }
+
+                @Override
+                public Object getAttribute(String name) {
+                    return c.getAttribute(name);
+                }
+            };
+        }
+        else if (credentials instanceof GuestCredentials) {
+            return new CredentialsInfo() {
+                @Override
+                public String getUserId() {
+                    return "anonymous";
+                }
+
+                @Override
+                public String[] getAttributeNames() {
+                    return new String[0]; 
+                }
+
+                @Override
+                public Object getAttribute(String name) {
+                    return null; 
+                }
+            };
+        }
+        else {
+            throw new LoginException(format("Login failed for {0}", credentials));
+        }
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/AuthenticatorImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,26 @@
+/*
+ * 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.security;
+
+public interface CredentialsInfo {
+    String getUserId();
+    String[] getAttributeNames();
+    Object getAttribute(String name);
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/security/CredentialsInfo.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,49 @@
+/*
+ * 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.state;
+
+import javax.jcr.RepositoryException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChangeLog implements Operation {
+    private final List<Operation> operations = new ArrayList<Operation>();
+
+    @Override
+    public void accept(Visitor visitor) throws RepositoryException {
+        for (Operation operation : operations) {
+            operation.accept(visitor);
+        }
+    }
+
+    public void addOperation(Operation operation) {
+        if (!(operation instanceof ChangeLog)) {
+            operations.add(operation);
+        }
+    }
+    
+    public void clear() {
+        operations.clear();
+    }
+
+    public boolean isEmpty() {
+        return operations.isEmpty();
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/ChangeLog.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,147 @@
+/*
+ * 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.state;
+
+import org.apache.jackrabbit.Path;
+import org.apache.jackrabbit.json.JsonValue;
+
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class NodeDelta {
+    private final Map<String, NodeDelta> childNodes = new HashMap<String, NodeDelta>();
+    private final Set<String> removedNodes = new HashSet<String>();
+    private final Map<String, NodeDelta> addedNodes = new HashMap<String, NodeDelta>();
+    private final Map<String, JsonValue> properties = new HashMap<String, JsonValue>();
+    private final Path persistentPath;
+    
+    private Path sessionPath;
+
+    public NodeDelta(Path sessionPath, Path persistentPath) {
+        this.sessionPath = sessionPath;
+        this.persistentPath = persistentPath;
+    }
+
+    public boolean hasChildNode(String name) {
+        return childNodes.containsKey(name);
+    }
+
+    public NodeDelta getChildNode(String name) {
+        return childNodes.get(name);
+    }
+
+    public boolean hasRemovedNode(String name) {
+        return removedNodes.contains(name);
+    }
+
+    public Set<String> getRemovedNodes() {
+        return removedNodes;
+    }
+
+    public boolean hasAddedNode(String name) {
+        return addedNodes.containsKey(name);
+    }
+
+    public NodeDelta getAddedNode(String name) {
+        return addedNodes.get(name);
+    }
+
+    public Map<String, NodeDelta> getAddedNodes() {
+        return addedNodes;
+    }
+
+    public boolean hasAddedProperty(String name) {
+        return properties.containsKey(name) && properties.get(name) != null;
+    }
+
+    public boolean hasRemovedProperty(String name) {
+        return properties.containsKey(name) && properties.get(name) == null;
+    }
+
+    public Map<String, JsonValue> getProperties() {
+        return properties;
+    }
+
+    public Path getPersistentPath() {
+        return persistentPath;
+    }
+
+    public Path getSessionPath() {
+        return sessionPath;
+    }
+
+    public void setSessionPath(Path sessionPath) {
+        this.sessionPath = sessionPath;
+    }
+
+    public boolean isNew() {
+        return persistentPath == null;
+    }
+
+    public boolean isModified() {
+        return addedNodes.isEmpty() && removedNodes.isEmpty() && properties.isEmpty();
+    }
+
+    public NodeDelta addNode(String name, NodeDelta delta) throws ItemExistsException {
+        if (childNodes.containsKey(name) || addedNodes.containsKey(name)) {
+            throw new ItemExistsException(name);
+        }
+
+        removedNodes.remove(name);
+        addedNodes.put(name, delta);
+        return delta;
+    }
+
+    public void removeNode(String name) throws ItemNotFoundException {
+        if (removedNodes.contains(name)) {
+            throw new ItemNotFoundException(name);
+        }
+
+        childNodes.remove(name);
+        addedNodes.remove(name);
+        removedNodes.add(name);
+    }
+    
+    public NodeDelta addChild(String name, NodeDelta delta) {
+        childNodes.put(name, delta);
+        return delta;
+    }
+
+    public void addProperty(String name, JsonValue value) throws ItemExistsException {
+        if (hasAddedProperty(name)) {
+            throw new ItemExistsException(name);
+        }
+
+        properties.put(name, value);
+    }
+
+    public void setValue(String name, JsonValue value) {
+        properties.put(name, value);
+    }
+
+    public JsonValue getProperty(String name) {
+        return properties.get(name);
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/NodeDelta.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,228 @@
+/*
+ * 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.state;
+
+import org.apache.jackrabbit.Path;
+import org.apache.jackrabbit.json.JsonValue;
+import org.apache.jackrabbit.json.JsonValue.JsonArray;
+
+import javax.jcr.RepositoryException;
+
+interface Operation {
+    void accept(Visitor visitor) throws RepositoryException;
+
+    interface Visitor {
+        void visit(AddNode addNode) throws RepositoryException;
+        void visit(AddProperty addProperty) throws RepositoryException;
+        void visit(SetValue setValue) throws RepositoryException;
+        void visit(RemoveNode removeNode) throws RepositoryException;
+        void visit(RemoveProperty removeProperty) throws RepositoryException;
+        void visit(Reorder reorder) throws RepositoryException;
+        void visit(SetMixin setMixin) throws RepositoryException;
+        void visit(SetPrimaryType setPrimaryType) throws RepositoryException;
+        void visit(Move move) throws RepositoryException;
+    }
+
+    class AddNode implements Operation {
+        private final Path parent;
+        private final String name;
+
+        public AddNode(Path parent, String name) {
+            this.parent = parent;
+            this.name = name;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getParent() {
+            return parent;
+        }
+
+        public String getName() {
+            return name;
+        }
+    }
+
+    class AddProperty implements Operation {
+        private final Path parent;
+        private final String name;
+        private final JsonValue value;
+
+        public AddProperty(Path parent, String name, JsonValue value) {
+            this.parent = parent;
+            this.name = name;
+            this.value = value;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getParent() {
+            return parent;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public JsonValue getValue() {
+            return value;
+        }
+    }
+
+    class SetValue implements Operation {
+        private final Path path;
+        private final JsonValue value;
+
+        public SetValue(Path path, JsonValue value) {
+            this.path = path;
+            this.value = value;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getPath() {
+            return path;
+        }
+
+        public JsonValue getValue() {
+            return value;
+        }
+    }
+
+    abstract class Remove implements Operation {
+        private final Path path;
+
+        protected Remove(Path path) {
+            this.path = path;
+        }
+
+        public Path getPath() {
+            return path;
+        }
+    }
+
+    class RemoveNode extends Remove {
+        public RemoveNode(Path path) {
+            super(path);
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+    }
+
+    class RemoveProperty extends Remove {
+        public RemoveProperty(Path path) {
+            super(path);
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+    }
+
+    class Reorder implements Operation {
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+    }
+
+    class SetMixin implements Operation {
+        private final Path path;
+        private final JsonArray mixins;
+
+        public SetMixin(Path path, JsonArray mixins) {
+            this.path = path;
+            this.mixins = mixins;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getPath() {
+            return path;
+        }
+
+        public JsonValue getMixins() {
+            return mixins;
+        }
+    }
+
+    class SetPrimaryType implements Operation {
+        private final Path path;
+        private final JsonValue primaryType;
+
+        public SetPrimaryType(Path path, JsonValue primaryType) {
+            this.path = path;
+            this.primaryType = primaryType;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getPath() {
+            return path;
+        }
+
+        public JsonValue getPrimaryType() {
+            return primaryType;
+        }
+    }
+
+    class Move implements Operation {
+        private final Path source;
+        private final Path destination;
+
+        public Move(Path source, Path destination) {
+            this.source = source;
+            this.destination = destination;
+        }
+
+        @Override
+        public void accept(Visitor visitor) throws RepositoryException {
+            visitor.visit(this);
+        }
+
+        public Path getSource() {
+            return source;
+        }
+
+        public Path getDestination() {
+            return destination;
+        }
+    }
+
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/Operation.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,343 @@
+/*
+ * 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.state;
+
+import org.apache.jackrabbit.Path;
+import org.apache.jackrabbit.json.JsonValue;
+import org.apache.jackrabbit.json.JsonValue.JsonArray;
+import org.apache.jackrabbit.json.JsonValue.JsonAtom;
+import org.apache.jackrabbit.state.Operation.AddNode;
+import org.apache.jackrabbit.state.Operation.AddProperty;
+import org.apache.jackrabbit.state.Operation.Move;
+import org.apache.jackrabbit.state.Operation.RemoveNode;
+import org.apache.jackrabbit.state.Operation.RemoveProperty;
+import org.apache.jackrabbit.state.Operation.Reorder;
+import org.apache.jackrabbit.state.Operation.SetMixin;
+import org.apache.jackrabbit.state.Operation.SetPrimaryType;
+import org.apache.jackrabbit.state.Operation.SetValue;
+import org.apache.jackrabbit.state.Operation.Visitor;
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.api.MicroKernelException;
+
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+public class TransientSpace {
+    private final ChangeLog changeLog = new ChangeLog();
+    private final MicroKernel microKernel;
+    private final Path rootPath;
+
+    private String revision;
+    private NodeDelta root;
+
+    public TransientSpace(MicroKernel microKernel, String revision, Path rootPath) {
+        this.microKernel = microKernel;
+        this.rootPath = rootPath;
+        this.revision = revision;
+        root = new NodeDelta(rootPath, rootPath);
+    }
+
+    public void apply(Operation operation) throws RepositoryException {
+        operation.accept(new Visitor() {
+            @Override
+            public void visit(Operation.AddNode addNode) throws RepositoryException {
+                Path parentPath = addNode.getParent();
+                String name = addNode.getName();
+                NodeDelta parent = getOrCreateNodeDelta(parentPath);
+                parent.addNode(name, new NodeDelta(parentPath.concat(name), null));
+            }
+
+            @Override
+            public void visit(Operation.AddProperty addProperty) throws RepositoryException {
+                NodeDelta parent = getOrCreateNodeDelta(addProperty.getParent());
+                parent.addProperty(addProperty.getName(), addProperty.getValue());
+            }
+
+            @Override
+            public void visit(Operation.SetValue setValue) throws RepositoryException {
+                Path path = setValue.getPath();
+                NodeDelta parent = getOrCreateNodeDelta(path.getParent());
+                parent.setValue(path.getName(), setValue.getValue());
+            }
+
+            @Override
+            public void visit(Operation.RemoveNode removeNode) throws RepositoryException {
+                Path path = removeNode.getPath();
+                NodeDelta parent = getOrCreateNodeDelta(path.getParent());
+                parent.removeNode(path.getName());
+            }
+
+            @Override
+            public void visit(RemoveProperty removeProperty) throws RepositoryException {
+                Path path = removeProperty.getPath();
+                NodeDelta parent = getOrCreateNodeDelta(path.getParent());
+                parent.setValue(path.getName(), JsonAtom.NULL);
+            }
+
+            @Override
+            public void visit(Operation.Reorder reorder) {
+                // todo implement visit(Reorder)
+            }
+
+            @Override
+            public void visit(Operation.SetMixin setMixin) throws RepositoryException {
+                NodeDelta parent = getOrCreateNodeDelta(setMixin.getPath());
+                parent.setValue("jcr:mixinTypes", setMixin.getMixins());
+            }
+
+            @Override
+            public void visit(Operation.SetPrimaryType setPrimaryType) throws RepositoryException {
+                NodeDelta parent = getOrCreateNodeDelta(setPrimaryType.getPath());
+                parent.setValue("jcr:primaryType", setPrimaryType.getPrimaryType());
+            }
+
+            @Override
+            public void visit(Operation.Move move) throws RepositoryException {
+                Path source = move.getSource();
+                Path destination = move.getDestination();
+
+                NodeDelta sourceNode = getOrCreateNodeDelta(source);
+                NodeDelta sourceParent = getOrCreateNodeDelta(source.getParent());
+                sourceParent.removeNode(source.getName());
+                sourceNode.setSessionPath(destination);
+
+                NodeDelta destinationParent = getOrCreateNodeDelta(destination.getParent());
+                destinationParent.addNode(destination.getName(), sourceNode);
+            }
+
+            private NodeDelta getOrCreateNodeDelta(Path path) throws PathNotFoundException {
+                String[] names = path.getNames();
+                NodeDelta delta = root;
+                for (String name : names) {
+                    if (delta.hasChildNode(name)) {
+                        delta = delta.getChildNode(name);
+                    }
+                    else if (delta.hasAddedNode(name)) {
+                        delta = delta.getAddedNode(name);
+                    }
+                    else if (delta.hasRemovedNode(name)) {
+                        throw new PathNotFoundException(path.toString());
+                    }
+                    else {
+                        Path persistedPath = delta.getPersistentPath();
+                        if (persistedPath == null) {
+                            throw new PathNotFoundException(path.toString());
+                        }
+
+                        persistedPath = persistedPath.concat(name);
+                        if (!microKernel.nodeExists(persistedPath.getMkPath(), revision)) {
+                            throw new PathNotFoundException(path.toString());
+                        }
+
+                        Path sessionPath = delta.getSessionPath().concat(name);
+                        delta = delta.addChild(name, new NodeDelta(sessionPath, persistedPath));
+                    }
+                }
+                return delta;
+            }
+        });
+
+        changeLog.addOperation(operation);
+    }
+
+    public NodeDelta getNodeDelta(final Path path) {
+        if (!rootPath.getWorkspace().equals(path.getWorkspace())) {
+            return new NodeDelta(path, path);
+        }
+
+        String[] names = path.getNames();
+        NodeDelta delta = root;
+        for (String name : names) {
+            if (delta.hasRemovedNode(name)) {
+                return null;
+            }
+            else if (delta.hasAddedNode(name)) {
+                delta = delta.getAddedNode(name);
+            }
+            else if (delta.hasChildNode(name)) {
+                delta = delta.getChildNode(name);
+            }
+            else {
+                return new NodeDelta(path, path);
+            }
+        }
+        return delta;
+    }
+
+    public ChangeLog getChangeLog() {
+        return changeLog;
+    }
+
+    public String refresh(boolean keepChanges) throws RepositoryException {
+        NodeDelta oldRoot = root;
+        try {
+            root = new NodeDelta(rootPath, rootPath);
+
+            if (keepChanges) {
+                apply(changeLog);
+            }
+            else {
+                changeLog.clear();
+            }
+
+            return revision = microKernel.getHeadRevision();
+        }
+        catch (RepositoryException e) {
+            root = oldRoot;
+            throw e;
+        }
+    }
+
+    public String save() throws RepositoryException {
+        try {
+            final StringBuilder jsop = new StringBuilder();
+
+            changeLog.accept(new Visitor() {
+                @Override
+                public void visit(AddNode addNode) {
+                    Path target = addNode.getParent().concat(addNode.getName());
+                    jsop.append("+\"")
+                        .append(target.getMkPath().substring(1))
+                        .append("\":")
+                        .append("{}")
+                        .append('\n');
+                }
+
+                @Override
+                public void visit(AddProperty addProperty) {
+                    Path target = addProperty.getParent().concat(addProperty.getName());
+                    jsop.append("^\"")
+                        .append(target.getMkPath().substring(1))
+                        .append("\":")
+                            .append(addProperty.getValue().toJson())
+                        .append('\n');
+                }
+
+                @Override
+                public void visit(SetValue setValue) {
+                    jsop.append("^\"")
+                        .append(setValue.getPath().getMkPath().substring(1))
+                        .append("\":")
+                        .append(setValue.getValue().toJson())
+                        .append('\n');
+                }
+
+                @Override
+                public void visit(RemoveNode removeNode) {
+                    jsop.append("-\"")
+                            .append(removeNode.getPath().getMkPath().substring(1))
+                            .append("\"\n");
+                }
+
+                @Override
+                public void visit(RemoveProperty removeProperty) {
+                    jsop.append("^\"")
+                            .append(removeProperty.getPath().getMkPath().substring(1))
+                            .append("\":null\n");
+                }
+
+                @Override
+                public void visit(Reorder reorder) throws UnsupportedRepositoryOperationException {
+                    throw new UnsupportedRepositoryOperationException("Reorder");
+                }
+
+                @Override
+                public void visit(SetMixin setMixin) {
+                    Path target = setMixin.getPath().concat("jcr:mixinTypes");
+                    jsop.append("^\"")
+                            .append(target.getMkPath().substring(1))
+                            .append("\":")
+                            .append(setMixin.getMixins().toJson())
+                            .append('\n');
+                }
+
+                @Override
+                public void visit(SetPrimaryType setPrimaryType) {
+                    Path target = setPrimaryType.getPath().concat("jcr:primaryType");
+                    jsop.append("^\"")
+                        .append(target.getMkPath().substring(1))
+                        .append("\":")
+                            .append(setPrimaryType.getPrimaryType().toJson())
+                        .append('\n');
+                }
+
+                @Override
+                public void visit(Move move) {
+                    jsop.append(">\"")
+                            .append(move.getSource().getMkPath().substring(1))
+                        .append("\":\"")
+                            .append(move.getDestination().getMkPath().substring(1))
+                        .append("\"\n");
+                }
+            });
+
+            revision = microKernel.commit("/", jsop.toString(), revision, "");
+            root = new NodeDelta(rootPath, rootPath);
+            changeLog.clear();
+            return revision;
+        }
+        catch (MicroKernelException e) {
+            throw new RepositoryException(e.getMessage(), e);
+        }
+    }
+
+    public boolean isDirty() {
+        return !changeLog.isEmpty();
+    }
+
+    //------------------------------------------< convenience >---
+
+    public void addNode(Path parent, String name) throws RepositoryException {
+        apply(new Operation.AddNode(parent, name));
+    }
+
+    public void addProperty(Path parent, String name, JsonValue value) throws RepositoryException {
+        apply(new Operation.AddProperty(parent, name, value));
+    }
+
+    public void setValue(Path path, JsonValue value) throws RepositoryException {
+        apply(new Operation.SetValue(path, value));
+    }
+
+    public void removeNode(Path path) throws RepositoryException {
+        apply(new Operation.RemoveNode(path));
+    }
+
+    public void removeProperty(Path path) throws RepositoryException {
+        apply(new Operation.RemoveProperty(path));
+    }
+
+    public void reorder() throws RepositoryException {
+        apply(new Operation.Reorder());
+    }
+
+    public void setMixin(Path path, JsonArray mixins) throws RepositoryException {
+        apply(new Operation.SetMixin(path, mixins));
+    }
+
+    public void setPrimaryType(Path path, JsonValue type) throws RepositoryException {
+        apply(new Operation.SetPrimaryType(path, type));
+    }
+
+    public void move(Path source, Path target) throws RepositoryException {
+        apply(new Operation.Move(source, target));
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/state/TransientSpace.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,64 @@
+/*
+ * 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.utils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public final class Arrays {
+    private Arrays() {}
+
+    public static <T> boolean contains(T[] array, T element) {
+        for (T t : array) {
+            if (element == null && t == null || element != null && element.equals(t)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static <T> Set<T> toSet(T... elements) {
+        return new HashSet<T>(java.util.Arrays.asList(elements));
+    }
+
+    public static <T> T[] add(T[] array, T value) {
+        T[] copy = java.util.Arrays.copyOf(array, array.length + 1);
+        copy[array.length] = value;
+        return copy;
+    }
+    
+    public static <T> T[] remove(T[] array, T value) {
+        List<T> copy = new ArrayList<T>(array.length);
+        for (T v : array) {
+            if (value == null) {
+                if (v != null) {
+                    copy.add(v);
+                }
+            }
+            else if (!value.equals(v)) {
+                copy.add(v);
+            }
+        }
+
+        return (T[]) copy.toArray();
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/Arrays.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,196 @@
+/*
+ * 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.utils;
+
+import org.apache.jackrabbit.json.JsonValue;
+import org.apache.jackrabbit.spi.commons.iterator.Iterators;
+import org.apache.jackrabbit.spi.commons.iterator.Predicate;
+import org.apache.jackrabbit.spi.commons.iterator.Transformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.Item;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.StringTokenizer;
+
+public abstract class ChildItemCollector<T extends Item> implements Iterable<T> {
+    static final Logger log = LoggerFactory.getLogger(ChildItemCollector.class);
+
+    static final char WILDCARD_CHAR = '*';
+    static final String OR = "|";
+
+    private final Iterator<Entry<String, JsonValue>> items;
+
+    protected ChildItemCollector(Iterator<Entry<String, JsonValue>> items) {
+        this.items = items;
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return Iterators.transformIterator(
+            Iterators.filterIterator(items,
+                    new Predicate<Entry<String, JsonValue>>() {
+                        @Override
+                        public boolean evaluate(Entry<String, JsonValue> entry) {
+                            return include(entry.getKey(), entry.getValue());
+                        }
+                    }),
+
+            new Transformer<Entry<String, JsonValue>, T>() {
+                @Override
+                public T transform(Entry<String, JsonValue> entry) {
+                    return createItem(entry.getKey(), entry.getValue());
+                }
+            });
+    }
+
+    protected abstract boolean include(String name, JsonValue value);
+    protected abstract T createItem(String name, JsonValue value);
+
+    /**
+     * Matches the name pattern against the specified name.
+     * <p/>
+     * The pattern may be a full name or a partial name with one or more
+     * wildcard characters ("*"), or a disjunction (using the "|" character
+     * to represent logical <i>OR</i>) of these. For example,
+     * <p/>
+     * {@code "jcr:*|foo:bar"}
+     * <p/>
+     * would match
+     * <p/>
+     * {@code "foo:bar"}, but also {@code "jcr:whatever"}.
+     * <p/>
+     * <pre>
+     * The EBNF for pattern is:
+     *
+     * namePattern ::= disjunct {'|' disjunct}
+     * disjunct ::= name [':' name]
+     * name ::= '*' |
+     *          ['*'] fragment {'*' fragment}['*']
+     * fragment ::= char {char}
+     * char ::= nonspace | ' '
+     * nonspace ::= (* Any Unicode character except:
+     *               '/', ':', '[', ']', '*',
+     *               ''', '"', '|' or any whitespace
+     *               character *)
+     * </pre>
+     * Note that leading and trailing whitespace around a pattern <i>is</i> ignored.
+     *
+     * @param name the name to test the pattern with
+     * @param pattern the pattern to be matched against the name
+     * @return true if the specified name matches the pattern
+     * @see javax.jcr.Node#getNodes(String)
+     */
+    public static boolean matches(String name, String pattern) {
+        StringTokenizer st = new StringTokenizer(pattern, OR, false);
+        while (st.hasMoreTokens()) {
+            // remove leading & trailing whitespace from token
+            String token = st.nextToken().trim();
+            if (internalMatches(name, token, 0, 0)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Matches the {@code nameGlob} strings in the passed array against
+     * the specified name.
+     * <p>
+     * A glob may be a full name or a partial name with one or more
+     * wildcard characters ("{@code *}").
+     * <p>
+     * Note that unlike in the case of the {@link #matches(String, String)}
+     * leading and trailing whitespace around a glob is <i>not</i> ignored.
+     *
+     * @param name the name to test the pattern with
+     * @param nameGlobs an array of globbing strings
+     * @return true if the specified name matches any of the globs
+     * @see javax.jcr.Node#getNodes(String[])
+     */
+    public static boolean matches(String name, String[] nameGlobs) {
+        for (String nameGlob : nameGlobs) {
+            // use globbing string as-is. Don't trim any leading/trailing whitespace
+            if (internalMatches(name, nameGlob, 0, 0)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Internal helper used to recursively match the pattern
+     *
+     * @param s       The string to be tested
+     * @param pattern The pattern
+     * @param sOff    offset within {@code s}
+     * @param pOff    offset within {@code pattern}.
+     * @return true if {@code s} matched pattern, else false.
+     */
+    private static boolean internalMatches(String s, String pattern, int sOff, int pOff) {
+        int pLen = pattern.length();
+        int sLen = s.length();
+
+        while (true) {
+            if (pOff >= pLen) {
+                if (sOff >= sLen) {
+                    return true;
+                } else if (s.charAt(sOff) == '[') {
+                    // check for subscript notation (e.g. "whatever[1]")
+                    // the entire pattern matched up to the subscript:
+                    // -> ignore the subscript
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+            if (sOff >= sLen && pattern.charAt(pOff) != WILDCARD_CHAR) {
+                return false;
+            }
+
+            // check for a '*' as the next pattern char; this is handled by
+            // a recursive call for each postfix of the name.
+            if (pattern.charAt(pOff) == WILDCARD_CHAR) {
+                if (++pOff >= pLen) {
+                    return true;
+                }
+
+                while (true) {
+                    if (internalMatches(s, pattern, sOff, pOff)) {
+                        return true;
+                    }
+                    if (sOff >= sLen) {
+                        return false;
+                    }
+                    sOff++;
+                }
+            }
+
+            if (pOff < pLen && sOff < sLen) {
+                if (pattern.charAt(pOff) != s.charAt(sOff)) {
+                    return false;
+                }
+            }
+            pOff++;
+            sOff++;
+        }
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/ChildItemCollector.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.utils;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class NodeIteratorAdapter extends RangeIteratorAdapter<Node> implements NodeIterator {
+
+    public NodeIteratorAdapter(Iterator<Node> iterator, long size) {
+        super(iterator, size);
+    }
+
+    public NodeIteratorAdapter(Iterator<Node> iterator) {
+        super(iterator);
+    }
+
+    public NodeIteratorAdapter(Collection<Node> nodes) {
+        super(nodes);
+    }
+
+    @Override
+    public Node nextNode() {
+        return next();
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/NodeIteratorAdapter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java?rev=1212018&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java (added)
+++ jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java Thu Dec  8 18:18:42 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.utils;
+
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class PropertyIteratorAdapter extends RangeIteratorAdapter<Property> implements PropertyIterator{
+
+    public PropertyIteratorAdapter(Iterator<Property> propertyIterator, long size) {
+        super(propertyIterator, size);
+    }
+
+    public PropertyIteratorAdapter(Iterator<Property> propertyIterator) {
+        super(propertyIterator);
+    }
+
+    public PropertyIteratorAdapter(Collection<Property> properties) {
+        super(properties);
+    }
+
+    @Override
+    public Property nextProperty() {
+        return next();
+    }
+}

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/sandbox/jackrabbit-microkernel/src/main/java/org/apache/jackrabbit/utils/PropertyIteratorAdapter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL