jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r922398 [2/2] - in /jackrabbit/sandbox/jackrabbit-j3: ./ 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/j3/ src/main/java/org/apache/jackra...
Date Fri, 12 Mar 2010 19:13:40 GMT
Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Bundle.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,584 @@
+/*
+ * 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.j3.mc;
+
+import javax.jcr.PropertyType;
+
+public class Bundle {
+
+    // types 0 (PropertyType.UNDEFINED) - 12 (PropertyType.DECIMAL) are used
+
+    private static final int BACK_POINTER = 42;
+    private static final int MULTI_VALUE = 43;
+    private static final int BINARY_REFERENCE = 44;
+    private static final int BOOLEAN_FALSE = 45;
+    private static final int BOOLEAN_TRUE = 46;
+    private static final int LONG_NEGATIVE = 47;
+    private static final int STRING_LEN_0_15 = 48;
+    private static final int INDEXED = 64;
+
+    /**
+     * The data itself.
+     */
+    private byte[] data;
+
+    /**
+     * Used while writing: back pointers.
+     */
+    private final int[] last = new int[64];
+
+    /**
+     * The current write or read position.
+     */
+    private int pos;
+
+    private Bundle(byte[] data) {
+        this.data = data;
+    }
+
+    /**
+     * Get the length of a String value.
+     *
+     * @param s the value
+     * @return the length
+     */
+    private int getStringLen(String s) {
+        int len = s.length();
+        return getStringWithoutLengthLen(s, len) + getVarIntLen(len);
+    }
+
+    private int getStringWithoutLengthLen(String s, int len) {
+        int plus = 0;
+        for (int i = 0; i < len; i++) {
+            char c = s.charAt(i);
+            if (c >= 0x800) {
+                plus += 2;
+            } else if (c >= 0x80) {
+                plus++;
+            }
+        }
+        return len + plus;
+    }
+
+    /**
+     * Read a String value.
+     * The current position is incremented.
+     *
+     * @return the value
+     */
+    private String readString() {
+        int len = readVarInt();
+        return readString(len);
+    }
+
+    private String readString(int len) {
+        byte[] buff = data;
+        int p = pos;
+        char[] chars = new char[len];
+        for (int i = 0; i < len; i++) {
+            int x = buff[p++] & 0xff;
+            if (x < 0x80) {
+                chars[i] = (char) x;
+            } else if (x >= 0xe0) {
+                chars[i] = (char) (((x & 0xf) << 12) + ((buff[p++] & 0x3f) << 6) + (buff[p++] & 0x3f));
+            } else {
+                chars[i] = (char) (((x & 0x1f) << 6) + (buff[p++] & 0x3f));
+            }
+        }
+        pos = p;
+        return new String(chars);
+    }
+
+    /**
+     * Write a String value.
+     * The current position is incremented.
+     *
+     * @param s the value
+     */
+    private void writeString(String s) {
+        int len = s.length();
+        checkCapacity(5 + len * 3);
+        writeVarInt(len);
+        writeStringWithoutLength(s, len);
+    }
+
+    private void writeStringWithoutLength(String s, int len) {
+        int p = pos;
+        byte[] buff = data;
+        for (int i = 0; i < len; i++) {
+            int c = s.charAt(i);
+            if (c < 0x80) {
+                buff[p++] = (byte) c;
+            } else if (c >= 0x800) {
+                buff[p++] = (byte) (0xe0 | (c >> 12));
+                buff[p++] = (byte) (((c >> 6) & 0x3f));
+                buff[p++] = (byte) (c & 0x3f);
+            } else {
+                buff[p++] = (byte) (0xc0 | (c >> 6));
+                buff[p++] = (byte) (c & 0x3f);
+            }
+        }
+        pos = p;
+    }
+
+    /**
+     * Create a new buffer.
+     *
+     * @param capacity the initial capacity of the buffer
+     * @return the buffer
+     */
+    public static Bundle create(int capacity) {
+        return new Bundle(new byte[capacity]);
+    }
+
+    /**
+     * Create a new buffer.
+     *
+     * @param data the data
+     * @return the buffer
+     */
+    public static Bundle create(byte[] data) {
+        return new Bundle(data);
+    }
+
+    /**
+     * Get the current write position of this buffer, which is the current
+     * length.
+     *
+     * @return the length
+     */
+    public int length() {
+        return pos;
+    }
+
+    /**
+     * Get the byte array used for this bundle.
+     *
+     * @return the byte array
+     */
+    public byte[] getBytes() {
+        byte[] b = new byte[pos];
+        System.arraycopy(data, 0, b, 0, pos);
+        return b;
+    }
+
+    /**
+     * Set the position to 0.
+     */
+    public void reset() {
+        pos = 0;
+    }
+
+    /**
+     * Append a number of bytes to this buffer.
+     *
+     * @param buff the data
+     * @param off the offset in the data
+     * @param len the length in bytes
+     */
+    private void write(byte[] buff, int off, int len) {
+        checkCapacity(len);
+        System.arraycopy(buff, off, data, pos, len);
+        pos += len;
+    }
+
+    /**
+     * Copy a number of bytes to the given buffer from the current position. The
+     * current position is incremented accordingly.
+     *
+     * @param buff the output buffer
+     * @param off the offset in the output buffer
+     * @param len the number of bytes to copy
+     */
+    private void read(byte[] buff, int off, int len) {
+        System.arraycopy(data, pos, buff, off, len);
+        pos += len;
+    }
+
+    /**
+     * Append one single byte.
+     *
+     * @param x the value
+     */
+    private void writeByte(byte x) {
+        data[pos++] = x;
+    }
+
+    /**
+     * Append a value.
+     *
+     * @param v the value
+     */
+    public Bundle writeVal(Val v) {
+        checkCapacity(16);
+        if (v.getIndex() > 0) {
+            writeVarInt(INDEXED + v.getIndex());
+            return this;
+        }
+        int start = pos;
+        int type = v.getType();
+        switch (type) {
+        case Val.TYPE_MULTI_VALUE: {
+            writeByte((byte) MULTI_VALUE);
+            writeVarInt(v.getArray().length);
+            for (Val x : v.getArray()) {
+                writeVal(x);
+            }
+            break;
+        }
+        case Val.TYPE_BINARY_REFERENCE:
+            writeByte((byte) BINARY_REFERENCE);
+            writeString(v.getString());
+            break;
+        case PropertyType.BOOLEAN:
+            writeByte((byte) (v == Val.TRUE ? BOOLEAN_TRUE : BOOLEAN_FALSE));
+            break;
+        case PropertyType.BINARY: {
+            writeByte((byte) type);
+            byte[] x = v.getBytes();
+            writeVarInt(x.length);
+            write(x, 0, x.length);
+            break;
+        }
+        case PropertyType.DOUBLE:
+            writeByte((byte) type);
+            writeVarLong(Long.reverseBytes(Double.doubleToLongBits(v.getDouble())));
+            break;
+        case PropertyType.LONG: {
+            long x = v.getLong();
+            if (x < 0) {
+                writeByte((byte) LONG_NEGATIVE);
+                writeVarLong(-x);
+            } else {
+                writeByte((byte) type);
+                writeVarLong(x);
+            }
+            break;
+        }
+        case PropertyType.STRING: {
+            String s = v.getString();
+            int len = s.length();
+            if (len < 16) {
+                writeByte((byte) (STRING_LEN_0_15 + len));
+                writeStringWithoutLength(s, len);
+            } else {
+                writeByte((byte) type);
+                writeString(s);
+            }
+            break;
+        }
+        case PropertyType.DATE:
+        case PropertyType.DECIMAL:
+        case PropertyType.NAME:
+        case PropertyType.PATH:
+        case PropertyType.REFERENCE:
+        case PropertyType.URI:
+        case PropertyType.WEAKREFERENCE:
+            writeByte((byte) type);
+            writeString(v.getString());
+            break;
+        default:
+            throw new IllegalArgumentException("type:" + v.getType());
+        }
+        int len = pos - start;
+        if (len > 8) {
+            int hash = data[start] ^ data[start + 1] ^ data[start + 2];
+            hash = hash & (last.length - 1);
+            int test = last[hash];
+            if (test <= 0 || test >= start) {
+                last[hash] = start + 1;
+            } else {
+                test--;
+                int i = 0;
+                for (; i < len; i++) {
+                    if (data[i + start] != data[test + i]) {
+                        break;
+                    }
+                }
+                if (i == len) {
+                    // write back pointer instead of the data
+                    pos = start;
+                    writeByte((byte) BACK_POINTER);
+                    writeVarInt(start - test);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Calculate the number of bytes required to encode the given value.
+     *
+     * @param v the value
+     * @return the number of bytes required to store this value
+     */
+    public int getValLen(Val v) {
+        if (v.getIndex() > 0) {
+            return getVarIntLen(INDEXED + v.getIndex());
+        }
+        int type = v.getType();
+        switch (type) {
+        case Val.TYPE_MULTI_VALUE: {
+            Val[] array = v.getArray();
+            int len = 1 + getVarLongLen(array.length);
+            for (Val x : array) {
+                len += getValLen(x);
+            }
+            return len;
+        }
+        case Val.TYPE_BINARY_REFERENCE:
+            return 1 + getStringLen(v.getString());
+        case PropertyType.BOOLEAN:
+            return 1;
+        case PropertyType.BINARY: {
+            byte[] x = v.getBytes();
+            return 1 + getVarIntLen(x.length) + x.length;
+        }
+        case PropertyType.DOUBLE: {
+            double x = v.getDouble();
+            return 1 + getVarLongLen(Long.reverseBytes(Double.doubleToLongBits(x)));
+        }
+        case PropertyType.LONG: {
+            long x = v.getLong();
+            if (x < 0) {
+                return 1 + getVarLongLen(-x);
+            } else {
+                return 1 + getVarLongLen(x);
+            }
+        }
+        case PropertyType.STRING: {
+            String s = v.getString();
+            int len = s.length();
+            if (len < 16) {
+                return 1 + getStringWithoutLengthLen(s, len);
+            } else {
+                return 1 + getStringLen(s);
+            }
+        }
+        case PropertyType.DATE:
+        case PropertyType.DECIMAL:
+        case PropertyType.NAME:
+        case PropertyType.PATH:
+        case PropertyType.REFERENCE:
+        case PropertyType.URI:
+        case PropertyType.WEAKREFERENCE:
+            return 1 + getStringLen(v.getString());
+        default:
+            throw new IllegalArgumentException("type:" + v.getType());
+        }
+    }
+
+    /**
+     * Read a value.
+     *
+     * @return the value
+     */
+    public Val readVal() {
+        int type = data[pos] & 255;
+        if (type >= INDEXED) {
+            return Val.getIndexed(readVarInt() - INDEXED);
+        }
+        pos++;
+        switch (type) {
+        case BACK_POINTER: {
+            int start = pos - 1;
+            int offset = readVarInt();
+            int old = pos;
+            pos = start - offset;
+            Val v = readVal();
+            pos = old;
+            return v;
+        }
+        case MULTI_VALUE: {
+            int len = readVarInt();
+            Val array[] = new Val[len];
+            for (int i=0; i<len; i++) {
+                array[i] = readVal();
+            }
+            return Val.get(array);
+        }
+        case BINARY_REFERENCE:
+            return Val.get(PropertyType.BINARY, readString());
+        case BOOLEAN_TRUE:
+            return Val.TRUE;
+        case BOOLEAN_FALSE:
+            return Val.FALSE;
+        case PropertyType.BINARY: {
+            byte[] x = new byte[readVarInt()];
+            read(x, 0, x.length);
+            return Val.get(x);
+        }
+        case PropertyType.DOUBLE: {
+            long x = Long.reverseBytes(readVarLong());
+            return Val.get(Double.longBitsToDouble(x));
+        }
+        case PropertyType.LONG:
+            return Val.get(readVarLong());
+        case LONG_NEGATIVE:
+            return Val.get(-readVarLong());
+        case PropertyType.STRING:
+        case PropertyType.DATE:
+        case PropertyType.DECIMAL:
+        case PropertyType.NAME:
+        case PropertyType.PATH:
+        case PropertyType.REFERENCE:
+        case PropertyType.URI:
+        case PropertyType.WEAKREFERENCE:
+            return Val.get(type, readString());
+        default:
+            if (type >= STRING_LEN_0_15 && type < STRING_LEN_0_15 + 16) {
+                return Val.get(readString(type - STRING_LEN_0_15));
+            }
+            throw new IllegalArgumentException("type:" + type);
+        }
+    }
+
+    /**
+     * The number of bytes required for a variable size int.
+     *
+     * @param x the value
+     * @return the len
+     */
+    private int getVarIntLen(int x) {
+        if ((x & (-1 << 7)) == 0) {
+            return 1;
+        } else if ((x & (-1 << 14)) == 0) {
+            return 2;
+        } else if ((x & (-1 << 21)) == 0) {
+            return 3;
+        } else if ((x & (-1 << 28)) == 0) {
+            return 4;
+        }
+        return 5;
+    }
+
+    /**
+     * Write a variable size int.
+     *
+     * @param x the value
+     */
+    public void writeVarInt(int x) {
+        while ((x & ~0x7f) != 0) {
+            data[pos++] = (byte) (0x80 | (x & 0x7f));
+            x >>>= 7;
+        }
+        data[pos++] = (byte) x;
+    }
+
+    /**
+     * Read a variable size int.
+     *
+     * @return the value
+     */
+    public int readVarInt() {
+        int b = data[pos];
+        if (b >= 0) {
+            pos++;
+            return b;
+        }
+        int x = b & 0x7f;
+        b = data[pos + 1];
+        if (b >= 0) {
+            pos += 2;
+            return x | (b << 7);
+        }
+        x |= (b & 0x7f) << 7;
+        b = data[pos + 2];
+        if (b >= 0) {
+            pos += 3;
+            return x | (b << 14);
+        }
+        x |= (b & 0x7f) << 14;
+        b = data[pos + 3];
+        if (b >= 0) {
+            pos += 4;
+            return x | b << 21;
+        }
+        x |= ((b & 0x7f) << 21) | (data[pos + 4] << 28);
+        pos += 5;
+        return x;
+    }
+
+    /**
+     * The number of bytes required for a variable size long.
+     *
+     * @param x the value
+     * @return the len
+     */
+    private int getVarLongLen(long x) {
+        int i = 1;
+        while (true) {
+            x >>>= 7;
+            if (x == 0) {
+                return i;
+            }
+            i++;
+        }
+    }
+
+    /**
+     * Write a variable size long.
+     *
+     * @param x the value
+     */
+    public void writeVarLong(long x) {
+        while ((x & ~0x7f) != 0) {
+            data[pos++] = (byte) ((x & 0x7f) | 0x80);
+            x >>>= 7;
+        }
+        data[pos++] = (byte) x;
+    }
+
+    /**
+     * Read a variable size long.
+     *
+     * @return the value
+     */
+    public long readVarLong() {
+        long x = data[pos++];
+        if (x >= 0) {
+            return x;
+        }
+        x &= 0x7f;
+        for (int s = 7;; s += 7) {
+            long b = data[pos++];
+            x |= (b & 0x7f) << s;
+            if (b >= 0) {
+                return x;
+            }
+        }
+    }
+
+    /**
+     * Check if there is still enough capacity in the buffer.
+     * This method extends the buffer if required.
+     *
+     * @param plus the number of additional bytes required
+     */
+    private void checkCapacity(int plus) {
+        if (pos + plus >= data.length) {
+            expand(plus);
+        }
+    }
+
+    private void expand(int plus) {
+        byte[] d = new byte[(data.length + plus) * 2];
+        System.arraycopy(data, 0, d, 0, data.length);
+        data = d;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/McException.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/McException.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/McException.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/McException.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,29 @@
+/*
+ * 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.j3.mc;
+
+public class McException extends RuntimeException {
+
+    public McException(String message) {
+        super(message);
+    }
+
+    public McException(Exception e) {
+        super(e);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/NodeData.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,242 @@
+/*
+ * 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.j3.mc;
+
+public class NodeData {
+
+    private final Val id;
+    private final Val primaryParentId;
+    private final long version;
+    private Val[] propertyValuePairs;
+    private Val[] childNameIdPairs;
+    private int cachedParentIndex;
+
+    public NodeData(Val id, Val primaryParentId, long version) {
+        this.id = id;
+        this.primaryParentId = primaryParentId;
+        this.version = version;
+    }
+
+    public NodeData clone() {
+        NodeData copy = new NodeData(id, primaryParentId, version);
+        copy.propertyValuePairs = propertyValuePairs;
+        copy.childNameIdPairs = childNameIdPairs;
+        return copy;
+    }
+
+    public void addChild(Val childName, Val childId) {
+        if (getChildId(childName) != null) {
+            throw new McException("duplicate node");
+        }
+        childNameIdPairs = updatePair(childNameIdPairs, childName, childId);
+    }
+
+    public Val getId() {
+        return id;
+    }
+
+    public Val getName(NodeData parent) {
+        if (parent == null) {
+            return Val.get("");
+        }
+        if (parent.childNameIdPairs == null) {
+            throw new McException("Child not found: " + id);
+        }
+        if (cachedParentIndex > parent.childNameIdPairs.length
+                || !parent.childNameIdPairs[cachedParentIndex + 1].equals(id)) {
+            for (int i = 0; i < parent.childNameIdPairs.length; i += 2) {
+                if (parent.childNameIdPairs[i + 1].equals(id)) {
+                    cachedParentIndex = i;
+                    break;
+                }
+            }
+            if (!parent.childNameIdPairs[cachedParentIndex + 1].equals(id)) {
+                throw new McException("Child not found: " + id);
+            }
+        }
+        return parent.childNameIdPairs[cachedParentIndex];
+    }
+
+    public Val getChildId(Val name) {
+        if (childNameIdPairs == null) {
+            return null;
+        }
+        int index = search(name, childNameIdPairs);
+        if (index < 0) {
+            return null;
+        }
+        Val childId = childNameIdPairs[index + 1];
+        return childId;
+    }
+
+    public Val getPropertyValue(Val propertyName) {
+        if (propertyValuePairs == null) {
+            return null;
+        }
+        int index = search(propertyName, propertyValuePairs);
+        if (index < 0) {
+            return null;
+        }
+        return propertyValuePairs[index + 1];
+    }
+
+    public void setPropertyValue(Val propertyName, Val newValue) {
+        propertyValuePairs = updatePair(propertyValuePairs, propertyName, newValue);
+    }
+
+    Val[] updatePair(Val[] pairs, Val key, Val value) {
+        if (pairs == null) {
+            if (value == null) {
+                return null;
+            } else {
+                return new Val[] { key, value };
+            }
+        }
+        int index = search(key, pairs);
+        if (index < 0) {
+            if (value == null) {
+                return pairs;
+            }
+            index = -index - 2;
+            Val[] newPairs = new Val[pairs.length + 2];
+            System.arraycopy(pairs, 0, newPairs, 0, index);
+            int len = newPairs.length - index;
+            if (len > 0) {
+                System.arraycopy(pairs, index, newPairs, index + 2, len - 2);
+            }
+            pairs = newPairs;
+        } else if (value == null) {
+            if (pairs.length == 2) {
+                return null;
+            }
+            Val[] newPairs = new Val[pairs.length - 2];
+            System.arraycopy(pairs, 0, newPairs, 0, index);
+            int len = newPairs.length - index;
+            if (len > 0) {
+                System.arraycopy(pairs, index + 2, newPairs, index, len);
+            }
+            return newPairs;
+        }
+        pairs[index] = key;
+        pairs[index + 1] = value;
+        return pairs;
+    }
+
+    private int search(Val key, Val[] pair) {
+        int low = 0;
+        int high = pair.length / 2 - 1;
+        while (low <= high) {
+            int mid = (low + high) >> 1;
+            Val middle = pair[mid * 2];
+            int result = middle.compareTo(key);
+            if (result < 0) {
+                low = mid + 1;
+            } else if (result > 0) {
+                high = mid - 1;
+            } else {
+                return mid * 2;
+            }
+        }
+        // not found
+        return -(low * 2 + 2);
+    }
+
+    int getMemoryUsed() {
+        int memory = 16;
+        if (propertyValuePairs != null) {
+            for (Val v : propertyValuePairs) {
+                memory += v.getMemoryUsed();
+            }
+        }
+        if (childNameIdPairs != null) {
+            for (Val v : childNameIdPairs) {
+                memory += v.getMemoryUsed();
+            }
+        }
+        return memory;
+    }
+
+    public String toString() {
+        StringBuilder buff = new StringBuilder();
+        buff.append("NodeData: id=" + id + " mainParent=" + primaryParentId + " version=" + version);
+        if (propertyValuePairs != null) {
+            buff.append(" { ");
+            for (int i = 0; i < propertyValuePairs.length; i += 2) {
+                if (i > 0) {
+                    buff.append(", ");
+                }
+                buff.append(propertyValuePairs[i]).append('=').append(propertyValuePairs[i + 1]);
+            }
+            buff.append(" }");
+        }
+        if (childNameIdPairs != null) {
+            buff.append(" [ ");
+            for (int i = 0; i < childNameIdPairs.length; i += 2) {
+                if (i > 0) {
+                    buff.append(", ");
+                }
+                buff.append(childNameIdPairs[i]).append('=').append(childNameIdPairs[i + 1]);
+            }
+            buff.append(" ]");
+        }
+        return buff.toString();
+    }
+
+    public static NodeData readFrom(Bundle bundle) {
+        Val id = bundle.readVal();
+        Val mainParentId = bundle.readVal();
+        if (mainParentId == Val.FALSE) {
+            mainParentId = null;
+        }
+        int version = bundle.readVarInt();
+        NodeData data = new NodeData(id, mainParentId, version);
+        Val children = bundle.readVal();
+        if (children != Val.FALSE) {
+            data.childNameIdPairs = children.getArray();
+        }
+        Val properties = bundle.readVal();
+        if (properties != Val.FALSE) {
+            data.propertyValuePairs = properties.getArray();
+        }
+        return data;
+    }
+
+    public void writeTo(Bundle bundle) {
+        bundle.writeVal(id);
+        bundle.writeVal(primaryParentId == null ? Val.FALSE : primaryParentId);
+        bundle.writeVarLong(version);
+        if (childNameIdPairs == null) {
+            bundle.writeVal(Val.FALSE);
+        } else {
+            bundle.writeVal(Val.get(childNameIdPairs));
+        }
+        if (propertyValuePairs == null) {
+            bundle.writeVal(Val.FALSE);
+        } else {
+            bundle.writeVal(Val.get(propertyValuePairs));
+        }
+    }
+
+    public long getVersion() {
+        return version;
+    }
+
+    public Val getPrimaryParentId() {
+        return primaryParentId;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Storage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Storage.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Storage.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Storage.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,25 @@
+/*
+ * 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.j3.mc;
+
+public interface Storage {
+
+    StorageSession openSession(String user, String password);
+
+    void close();
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/StorageSession.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,35 @@
+/*
+ * 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.j3.mc;
+
+public interface StorageSession {
+
+    void close();
+
+    Val getRootNodeId();
+
+    NodeData getNode(Val nodeId);
+
+    Val newNodeId(Val parentId);
+
+    void save(NodeData[] changed);
+
+    Val convertIdentifierToNodeId(String id);
+
+    String convertNodeIdToIdentifier(Val nodeId);
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/Val.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,384 @@
+/*
+ * 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.j3.mc;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import javax.jcr.PropertyType;
+
+public class Val implements Comparable<Val> {
+
+    public static final Val TRUE = new Val(PropertyType.BOOLEAN, 0, true);
+    public static final Val FALSE = new Val(PropertyType.BOOLEAN, 0, false);
+
+    public static final int TYPE_MULTI_VALUE = 43;
+    public static final int TYPE_BINARY_REFERENCE = 44;
+
+    private static final int CACHE_SIZE = 1024;
+    private static final Val[] CACHE = new Val[CACHE_SIZE];
+
+    private static final String EMPTY_STRING = "";
+    private static final Val STRING_0 = new Val(PropertyType.STRING, 0, EMPTY_STRING);
+
+    private static final HashMap<Val, Integer> INDEX_MAP = new HashMap<Val, Integer>();
+
+    private static final Val[] INDEXED = new Val[128];
+
+    static {
+        // index 0 is not used
+        Val[] indexed = new Val[] {
+            Val.get(-1),
+            Val.get(0),
+            Val.get(1),
+            Val.get(2),
+            Val.get(3),
+            Val.get(4),
+            Val.get(5),
+            Val.get(6),
+            Val.get(7),
+            Val.get(0.0d),
+            Val.get(1.0d),
+            Val.get("http://www.jcp.org/jcr/1.0"),
+            Val.get("http://www.jcp.org/jcr/mix/1.0"),
+            Val.get("http://www.jcp.org/jcr/nt/1.0"),
+            Val.get("http://www.jcp.org/jcr/sv/1.0"),
+            Val.get("activity"),
+            Val.get("address"),
+            Val.get("autocreated"),
+            Val.get("base"),
+            Val.get("childNodeDefinition"),
+            Val.get("childVersionHistory"),
+            Val.get("configuration"),
+            Val.get("content"),
+            Val.get("copiedFrom"),
+            Val.get("created"),
+            Val.get("createdBy"),
+            Val.get("data"),
+            Val.get("defaultPrimaryType"),
+            Val.get("defaultValues"),
+            Val.get("description"),
+            Val.get("encoding"),
+            Val.get("etag"),
+            Val.get("file"),
+            Val.get("folder"),
+            Val.get("frozenMixinTypes"),
+            Val.get("frozenNode"),
+            Val.get("frozenPrimaryType"),
+            Val.get("frozenUuid"),
+            Val.get("hasOrderableChildNodes"),
+            Val.get("hierarchyNode"),
+            Val.get("host"),
+            Val.get("id"),
+            Val.get("internal"),
+            Val.get("isCheckedOut"),
+            Val.get("jcr"),
+            Val.get("key"),
+            Val.get("language"),
+            Val.get("lastModified"),
+            Val.get("lastModifiedBy"),
+            Val.get("lifecycle"),
+            Val.get("linkedFile"),
+            Val.get("mandatory"),
+            Val.get("mergeFailed"),
+            Val.get("message"),
+            Val.get("mimeType"),
+            Val.get("mixin"),
+            Val.get("mixinTypes"),
+            Val.get("multiple"),
+            Val.get("name"),
+            Val.get("nodeTypeName"),
+            Val.get("nt"),
+            Val.get("onParentVersion"),
+            Val.get("orderable"),
+            Val.get("path"),
+            Val.get("port"),
+            Val.get("predecessors"),
+            Val.get("primaryItemName"),
+            Val.get("primaryType"),
+            Val.get("propertyDefinition"),
+            Val.get("protected"),
+            Val.get("protocol"),
+            Val.get("query"),
+            Val.get("referenceable"),
+            Val.get("repository"),
+            Val.get("requiredPrimaryTypes"),
+            Val.get("requiredType"),
+            Val.get("resource"),
+            Val.get("resourceType"),
+            Val.get("root"),
+            Val.get("rootVersion"),
+            Val.get("sameNameSiblings"),
+            Val.get("share"),
+            Val.get("shareable"),
+            Val.get("simpleVersionable"),
+            Val.get("sling"),
+            Val.get("successors"),
+            Val.get("supertypes"),
+            Val.get("system"),
+            Val.get("text"),
+            Val.get("title"),
+            Val.get("type"),
+            Val.get("unfiled"),
+            Val.get("unstructured"),
+            Val.get("uuid"),
+            Val.get("valueConstraints"),
+            Val.get("version"),
+            Val.get("versionable"),
+            Val.get("versionableUuid"),
+            Val.get("versionedChild"),
+            Val.get("versionHistory"),
+            Val.get("versionLabels"),
+            Val.get("versionStorage"),
+            Val.get("workspace"),
+            Val.get("http://sling.apache.org/jcr/event/1.0"),
+            Val.get("http://sling.apache.org/jcr/sling/1.0"),
+            Val.get("http://www.day.com/crx/1.0"),
+            Val.get("http://www.day.com/crx/replication/1.0"),
+            Val.get("http://www.day.com/dam/1.0"),
+            Val.get("http://www.day.com/jcr/cq/1.0"),
+            Val.get("http://www.day.com/jcr/crxde/1.0"),
+            Val.get("http://www.day.com/jcr/vault/1.0"),
+            Val.get("http://www.day.com/jcr/wiki/1.0"),
+            Val.get("http://www.w3.org/2001/XMLSchema"),
+            Val.get("http://www.w3.org/2004/10/xpath-functions"),
+            Val.get("http://www.w3.org/2005/xpath-functions"),
+            Val.get("http://www.w3.org/XML/1998/namespace"),
+        };
+        int i = 0;
+        for (Val v : indexed) {
+            v.index = (short) i;
+            INDEXED[i] = v;
+            INDEX_MAP.put(v, i);
+            i++;
+        }
+    }
+
+    private final short type;
+    private short index;
+    private final Object value;
+
+    private Val(int type, int index, Object value) {
+        this.type = (short) type;
+        this.index = (short) index;
+        this.value = value;
+    }
+
+    public static Val getIndexed(int index) {
+        return INDEXED[index];
+    }
+
+    private static Val cache(int type, Object value) {
+        Val v = new Val(type, 0, value);
+        Integer index = INDEX_MAP.get(v);
+        if (index != null) {
+            return INDEXED[index];
+        }
+        int hash = v.hashCode();
+        int cacheIndex = hash & (CACHE_SIZE - 1);
+        Val cached = CACHE[cacheIndex];
+        if (cached != null && v.equals(cached)) {
+            return cached;
+        }
+        CACHE[cacheIndex] = v;
+        return v;
+    }
+
+    public static Val get(Val... array) {
+        if (array == null) {
+            throw new NullPointerException();
+        }
+        return new Val(TYPE_MULTI_VALUE, 0, array);
+    }
+
+    public static Val get(boolean x) {
+        return x ? TRUE : FALSE;
+    }
+
+    public static Val get(long x) {
+        return cache(PropertyType.LONG, Long.valueOf(x));
+    }
+
+    public static Val get(double x) {
+        return cache(PropertyType.DOUBLE, Double.valueOf(x));
+    }
+
+    public static Val get(byte[] x) {
+        return new Val(PropertyType.BINARY, 0, x);
+    }
+
+    public static Val get(String x) {
+        if (x.length() == 0) {
+            return STRING_0;
+        }
+        return cache(PropertyType.STRING, x);
+    }
+
+    public static Val get(int type, String x) {
+        if (x.length() == 0) {
+            x = EMPTY_STRING;
+        }
+        switch (type) {
+        case PropertyType.DECIMAL:
+        case PropertyType.DATE:
+        case PropertyType.NAME:
+        case PropertyType.PATH:
+        case PropertyType.REFERENCE:
+        case PropertyType.STRING:
+        case PropertyType.URI:
+        case PropertyType.WEAKREFERENCE:
+            return cache(type, x);
+        case PropertyType.BINARY:
+            return cache(TYPE_BINARY_REFERENCE, x);
+        }
+        throw new IllegalArgumentException("type: " + type + " value: " + x);
+    }
+
+    public int hashCode() {
+        switch (type) {
+        case PropertyType.BINARY:
+            return getType() ^ Arrays.hashCode(getBytes());
+        case TYPE_MULTI_VALUE:
+            return getType() ^ Arrays.hashCode(getArray());
+        }
+        return getType() ^ value.hashCode();
+    }
+
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof Val) {
+            Val v = (Val) other;
+            if (v.type != type) {
+                return false;
+            }
+            switch (type) {
+            case PropertyType.BINARY:
+                return Arrays.equals(getBytes(), v.getBytes());
+            case TYPE_MULTI_VALUE:
+                return Arrays.equals(getArray(), v.getArray());
+            }
+            return v.value.equals(value);
+        }
+        return false;
+    }
+
+    public String toString() {
+        switch (type) {
+        case TYPE_MULTI_VALUE: {
+            StringBuilder buff = new StringBuilder("[ ");
+            int i = 0;
+            for (Val v : (Val[]) value) {
+                if (i++ > 0) {
+                    buff.append(", ");
+                }
+                buff.append(v.toString());
+            }
+            return buff.append(" ]").toString();
+        }
+        case TYPE_BINARY_REFERENCE: {
+            return "binaryRef:" + value;
+        }
+        default:
+            return value + ":" + PropertyType.nameFromValue(type);
+        }
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public String getString() {
+        return value.toString();
+    }
+
+    public double getDouble() {
+        return (Double) value;
+    }
+
+    public byte[] getBytes() {
+        return (byte[]) value;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public Val[] getArray() {
+        return (Val[]) value;
+    }
+
+    public long getLong() {
+        return (Long) value;
+    }
+
+    public int getMemoryUsed() {
+        if (index == 0) {
+            return 0;
+        }
+        switch (type) {
+        case PropertyType.BINARY:
+            return 32 + getBytes().length;
+        case PropertyType.LONG:
+        case PropertyType.DOUBLE:
+            return 16;
+        }
+        return 32 + getString().length() * 2;
+    }
+
+    public int compareTo(Val o) {
+        int result = compareInt(type, o.type);
+        if (result != 0) {
+            return result;
+        }
+        switch (type) {
+        case PropertyType.BINARY:
+            result = compareNotNull(getBytes(), o.getBytes());
+            break;
+        case PropertyType.LONG:
+            result = compareLong(getLong(), o.getLong());
+            break;
+        case PropertyType.DOUBLE:
+            result = Double.compare(getDouble(), o.getDouble());
+            break;
+        default:
+            result = getString().compareTo(o.getString());
+        }
+        return result;
+    }
+
+    public static int compareInt(int a, int b) {
+        return a == b ? 0 : a < b ? -1 : 1;
+    }
+
+    public static int compareLong(long a, long b) {
+        return a == b ? 0 : a < b ? -1 : 1;
+    }
+
+    public static int compareNotNull(byte[] data1, byte[] data2) {
+        int len = Math.min(data1.length, data2.length);
+        for (int i = 0; i < len; i++) {
+            byte b = data1[i];
+            byte b2 = data2[i];
+            if (b != b2) {
+                return b > b2 ? 1 : -1;
+            }
+        }
+        return Integer.signum(data1.length - data2.length);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorage.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,83 @@
+/*
+ * 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.j3.mc.jdbc;
+
+import org.apache.jackrabbit.j3.mc.McException;
+import org.apache.jackrabbit.j3.mc.NodeData;
+import org.apache.jackrabbit.j3.mc.Storage;
+import org.apache.jackrabbit.j3.mc.StorageSession;
+import org.apache.jackrabbit.j3.mc.Val;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class JdbcStorage implements Storage {
+
+    private final String url;
+    private boolean initDone;
+    private final static Val rootNodeId = Val.get(0);
+    private AtomicLong nextNodeId;
+
+    public JdbcStorage(String url) {
+        this.url = url;
+    }
+
+    public StorageSession openSession(String user, String password) {
+        try {
+            Connection conn = JdbcUtils.getConnection(null, url, user, password);
+            JdbcStorageSession session = new JdbcStorageSession(this, conn);
+            init(conn, session);
+            return session;
+        } catch (SQLException e) {
+            throw new McException(e);
+        }
+    }
+
+    private synchronized void init(Connection conn, JdbcStorageSession session) {
+        if (initDone) {
+            return;
+        }
+        try {
+            Statement stat = conn.createStatement();
+            stat.execute("create table if not exists bundles(id bigint primary key, version bigint, data binary)");
+            ResultSet rs = stat.executeQuery("select max(id) from bundles");
+            rs.next();
+            nextNodeId = new AtomicLong(rs.getLong(1) + 1);
+            if (rs.wasNull()) {
+                NodeData root = new NodeData(rootNodeId, null, 0);
+                session.save(new NodeData[] { root });
+            }
+        } catch (SQLException e) {
+            throw new McException(e);
+        }
+        initDone = true;
+    }
+
+    public void close() {
+    }
+
+    Val newNodeId() {
+        return Val.get(nextNodeId.getAndIncrement());
+    }
+
+    Val getRootNodeId() {
+        return rootNodeId;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcStorageSession.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,111 @@
+/*
+ * 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.j3.mc.jdbc;
+
+import org.apache.jackrabbit.j3.mc.Bundle;
+import org.apache.jackrabbit.j3.mc.McException;
+import org.apache.jackrabbit.j3.mc.NodeData;
+import org.apache.jackrabbit.j3.mc.StorageSession;
+import org.apache.jackrabbit.j3.mc.Val;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+public class JdbcStorageSession implements StorageSession {
+
+    private final JdbcStorage storage;
+    private final Connection conn;
+    private final HashMap<String, PreparedStatement> prepared = new HashMap<String, PreparedStatement>();
+    private final Bundle bundle = Bundle.create(512);
+
+    JdbcStorageSession(JdbcStorage storage, Connection conn) {
+        this.storage = storage;
+        this.conn = conn;
+    }
+
+    private PreparedStatement prepare(String sql) throws SQLException {
+        PreparedStatement p = prepared.get(sql);
+        if (p == null) {
+            p = conn.prepareStatement(sql);
+            prepared.put(sql, p);
+        }
+        return p;
+    }
+
+    public void close() {
+        try {
+            conn.close();
+        } catch (SQLException e) {
+            throw new McException(e);
+        }
+    }
+
+    public Val getRootNodeId() {
+        return storage.getRootNodeId();
+    }
+
+    public NodeData getNode(Val nodeId) {
+        try {
+            PreparedStatement p = prepare("select data from bundles where id = ?");
+            p.setLong(1, nodeId.getLong());
+            ResultSet rs = p.executeQuery();
+            if (!rs.next()) {
+                rs.close();
+                return null;
+            }
+            byte[] data = rs.getBytes(1);
+            Bundle bundle = Bundle.create(data);
+            NodeData node = NodeData.readFrom(bundle);
+            rs.close();
+            return node;
+        } catch (SQLException e) {
+            throw new McException(e);
+        }
+    }
+
+    public Val newNodeId(Val parentId) {
+        return storage.newNodeId();
+    }
+
+    public void save(NodeData[] changed) {
+        try {
+            PreparedStatement p = prepare("merge into bundles(id, version, data) values(?, ?, ?)");
+            for (NodeData n : changed) {
+                p.setLong(1, n.getId().getLong());
+                p.setLong(2, n.getVersion());
+                bundle.reset();
+                n.writeTo(bundle);
+                p.setBytes(3, bundle.getBytes());
+                p.executeUpdate();
+            }
+        } catch (SQLException e) {
+            throw new McException(e);
+        }
+    }
+
+    public Val convertIdentifierToNodeId(String id) {
+        return Val.get(Long.parseLong(id));
+    }
+
+    public String convertNodeIdToIdentifier(Val nodeId) {
+        return nodeId.getString();
+    }
+
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcUtils.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcUtils.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/jdbc/JdbcUtils.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,186 @@
+/*
+ * 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.j3.mc.jdbc;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import javax.naming.Context;
+import javax.sql.DataSource;
+
+/**
+ * This is a utility class with JDBC helper functions.
+ */
+public class JdbcUtils {
+
+    private static final String[] DRIVERS = {
+        "h2:", "org.h2.Driver",
+        "Cache:", "com.intersys.jdbc.CacheDriver",
+        "daffodilDB://", "in.co.daffodil.db.rmi.RmiDaffodilDBDriver",
+        "daffodil", "in.co.daffodil.db.jdbc.DaffodilDBDriver",
+        "db2:", "COM.ibm.db2.jdbc.net.DB2Driver",
+        "derby:net:", "org.apache.derby.jdbc.ClientDriver",
+        "derby://", "org.apache.derby.jdbc.ClientDriver",
+        "derby:", "org.apache.derby.jdbc.EmbeddedDriver",
+        "FrontBase:", "com.frontbase.jdbc.FBJDriver",
+        "firebirdsql:", "org.firebirdsql.jdbc.FBDriver",
+        "hsqldb:", "org.hsqldb.jdbcDriver",
+        "informix-sqli:", "com.informix.jdbc.IfxDriver",
+        "jtds:", "net.sourceforge.jtds.jdbc.Driver",
+        "microsoft:", "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+        "mimer:", "com.mimer.jdbc.Driver",
+        "mysql:", "com.mysql.jdbc.Driver",
+        "odbc:", "sun.jdbc.odbc.JdbcOdbcDriver",
+        "oracle:", "oracle.jdbc.driver.OracleDriver",
+        "pervasive:", "com.pervasive.jdbc.v2.Driver",
+        "pointbase:micro:", "com.pointbase.me.jdbc.jdbcDriver",
+        "pointbase:", "com.pointbase.jdbc.jdbcUniversalDriver",
+        "postgresql:", "org.postgresql.Driver",
+        "sybase:", "com.sybase.jdbc3.jdbc.SybDriver",
+        "sqlserver:", "com.microsoft.sqlserver.jdbc.SQLServerDriver",
+        "teradata:", "com.ncr.teradata.TeraDriver",
+    };
+
+    private JdbcUtils() {
+        // utility class
+    }
+
+    /**
+     * Close a statement without throwing an exception.
+     *
+     * @param stat the statement or null
+     */
+    public static void closeSilently(Statement stat) {
+        if (stat != null) {
+            try {
+                stat.close();
+            } catch (SQLException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Close a connection without throwing an exception.
+     *
+     * @param conn the connection or null
+     */
+    public static void closeSilently(Connection conn) {
+        if (conn != null) {
+            try {
+                conn.close();
+            } catch (SQLException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Close a result set without throwing an exception.
+     *
+     * @param rs the result set or null
+     */
+    public static void closeSilently(ResultSet rs) {
+        if (rs != null) {
+            try {
+                rs.close();
+            } catch (SQLException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Open a new database connection with the given settings.
+     *
+     * @param driver the driver class name
+     * @param url the database URL
+     * @param user the user name
+     * @param password the password
+     * @return the database connection
+     */
+    public static Connection getConnection(String driver, String url, String user, String password) throws SQLException {
+        Properties prop = new Properties();
+        if (user != null) {
+            prop.setProperty("user", user);
+        }
+        if (password != null) {
+            prop.setProperty("password", password);
+        }
+        return getConnection(driver, url, prop);
+    }
+
+    /**
+     * Open a new database connection with the given settings.
+     *
+     * @param driver the driver class name
+     * @param url the database URL
+     * @param prop the properties containing at least the user name and password
+     * @return the database connection
+     */
+    public static Connection getConnection(String driver, String url, Properties prop) throws SQLException {
+        try {
+            if (driver == null || driver.length() == 0) {
+                driver = getDriver(url);
+            }
+            Class< ? > d = Class.forName(driver);
+            if (java.sql.Driver.class.isAssignableFrom(d)) {
+                return DriverManager.getConnection(url, prop);
+            } else if (javax.naming.Context.class.isAssignableFrom(d)) {
+                // JNDI context
+                Context context = (Context) d.newInstance();
+                DataSource ds = (DataSource) context.lookup(url);
+                String user = prop.getProperty("user");
+                String password = prop.getProperty("password");
+                if (user == null && password == null) {
+                    return ds.getConnection();
+                }
+                return ds.getConnection(user, password);
+            } else {
+                return DriverManager.getConnection(url, prop);
+            }
+        } catch (Exception e) {
+            SQLException e2 = new SQLException("Can not open connection for url " + url + " " + prop);
+            e2.initCause(e);
+            throw e2;
+        }
+    }
+
+    /**
+     * Get the driver class name for the given URL, or null if the URL is
+     * unknown.
+     *
+     * @param url the database URL
+     * @return the driver class name
+     */
+    public static String getDriver(String url) {
+        if (url.startsWith("jdbc:")) {
+            url = url.substring("jdbc:".length());
+            for (int i = 0; i < DRIVERS.length; i += 2) {
+                String prefix = DRIVERS[i];
+                if (url.startsWith(prefix)) {
+                    return DRIVERS[i + 1];
+                }
+            }
+        }
+        return null;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorage.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,52 @@
+/*
+ * 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.j3.mc.mem;
+
+import org.apache.jackrabbit.j3.mc.Val;
+import org.apache.jackrabbit.j3.mc.NodeData;
+import org.apache.jackrabbit.j3.mc.Storage;
+import org.apache.jackrabbit.j3.mc.StorageSession;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class MemStorage implements Storage {
+
+    private final static Val rootNodeId = Val.get(0);
+    private final HashMap<Val, NodeData> content = new HashMap<Val, NodeData>();
+    private AtomicLong nextNodeId = new AtomicLong(1);
+
+    public MemStorage() {
+        NodeData root = new NodeData(rootNodeId, null, 0);
+        content.put(rootNodeId, root);
+    }
+
+    public void close() {
+    }
+
+    public StorageSession openSession(String user, String password) {
+        return new MemStorageSession(this, content);
+    }
+
+    public Val newNodeId() {
+        return Val.get(nextNodeId.getAndIncrement());
+    }
+
+    Val getRootNodeId() {
+        return rootNodeId;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/mc/mem/MemStorageSession.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,65 @@
+/*
+ * 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.j3.mc.mem;
+
+import java.util.HashMap;
+import org.apache.jackrabbit.j3.mc.NodeData;
+import org.apache.jackrabbit.j3.mc.StorageSession;
+import org.apache.jackrabbit.j3.mc.Val;
+
+public class MemStorageSession implements StorageSession {
+
+    private final MemStorage storage;
+    private final HashMap<Val, NodeData> content;
+
+    MemStorageSession(MemStorage storage, HashMap<Val, NodeData> content) {
+        this.storage = storage;
+        this.content = content;
+    }
+
+    public void close() {
+    }
+
+    public NodeData getNode(Val nodeId) {
+        return content.get(nodeId);
+    }
+
+    public Val getRootNodeId() {
+        return storage.getRootNodeId();
+    }
+
+    public Val newNodeId(Val parentId) {
+        return storage.newNodeId();
+    }
+
+    public void save(NodeData[] changed) {
+        for (NodeData n : changed) {
+            synchronized (storage) {
+                content.put(n.getId(), n);
+            }
+        }
+    }
+
+    public Val convertIdentifierToNodeId(String id) {
+        return Val.get(Long.parseLong(id));
+    }
+
+    public String convertNodeIdToIdentifier(Val nodeId) {
+        return nodeId.getString();
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/main/java/org/apache/jackrabbit/j3/observation/EventImpl.java Fri Mar 12 19:13:39 2010
@@ -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.j3.observation;
+
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import org.apache.jackrabbit.j3.SessionImpl;
+import org.apache.jackrabbit.j3.mc.Val;
+
+public class EventImpl implements Event {
+
+    private SessionImpl session;
+    private int eventType;
+    private Val nodeId;
+    private Val propertyName;
+    private long persistedDate;
+
+    public String getUserID() {
+        return session.getUserID();
+    }
+
+    public int getType() {
+        return eventType;
+    }
+
+    public long getDate() throws RepositoryException {
+        return persistedDate;
+    }
+
+    public String getIdentifier() throws RepositoryException {
+        return session.getStorageSession().convertNodeIdToIdentifier(nodeId);
+    }
+
+    public Map getInfo() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getPath() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getUserData() throws RepositoryException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestAll.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,44 @@
+/*
+ * 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.j3;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class TestAll {
+
+    /**
+     * Returns a <code>Test</code> suite that executes all tests inside this
+     * package.
+     *
+     * @return a <code>Test</code> suite that executes all tests inside this
+     *         package.
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite("org.apache.jackrabbit.j3");
+
+        suite.addTestSuite(TestBundle.class);
+
+        for (int i=0; i<2; i++) {
+            suite.addTestSuite(TestConcurrentWrite.class);
+            suite.addTestSuite(TestSimple.class);
+            suite.addTestSuite(TestNextConfiguration.class);
+        }
+
+        return suite;
+    }
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBase.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,60 @@
+/*
+ * 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.j3;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.jcr.LoginException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import junit.framework.TestCase;
+
+public class TestBase extends TestCase {
+
+    protected static int configurationId;
+
+    private Repository repository;
+    protected Session session;
+    private static final String[] URL = new String[] {
+        "mem:",
+        "jdbc:h2:mem:test"
+    };
+
+    public void setUp() throws Exception {
+        String factoryClass = "org.apache.jackrabbit.j3.RepositoryFactoryImpl";
+        String url = URL[configurationId];
+        RepositoryFactory factory = (RepositoryFactory) Class.forName(factoryClass).newInstance();
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("url", url);
+        repository = factory.getRepository(parameters);
+
+        session = openSession();
+    }
+
+    public void tearDown() throws Exception {
+        session.logout();
+    }
+
+    protected Session openSession() throws LoginException, RepositoryException {
+        SimpleCredentials credentials = new SimpleCredentials("sa", "sa".toCharArray());
+        return repository.login(credentials);
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestBundle.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,97 @@
+/*
+ * 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.j3;
+
+import javax.jcr.PropertyType;
+import junit.framework.TestCase;
+import org.apache.jackrabbit.j3.mc.Bundle;
+import org.apache.jackrabbit.j3.mc.Val;
+
+public class TestBundle extends TestCase {
+
+    public void testBundle() {
+        Bundle bundle = Bundle.create(512);
+        bundle.writeVal(Val.get("Hello")).writeVal(Val.get("World"));
+        assertEquals(12, bundle.length());
+        bundle.reset();
+        assertEquals("Hello", bundle.readVal().getString());
+        assertEquals("World", bundle.readVal().getString());
+        testLength(Val.TRUE);
+        testLength(Val.get(false));
+        testLength(Val.get(true));
+        testLength(Val.get(5));
+        testLength(Val.get(10));
+        testLength(Val.get(10000));
+        testLength(Val.get(100000000));
+        testLength(Val.get(10000000000L));
+        testLength(Val.get(1000000000000L));
+        testLength(Val.get(-100));
+        testLength(Val.get(""));
+        testLength(Val.get("unstructured"));
+        testLength(Val.get("lastModifiedBy"));
+        testLength(Val.get("http://www.jcp.org/jcr/mix/1.0"));
+        testLength(Val.get(0.0));
+        testLength(Val.get(1.0));
+        testLength(Val.get(12.0));
+        testLength(Val.get(123.0));
+        testLength(Val.get(1234.0));
+        testLength(Val.get(-1.0));
+        testLength(Val.get(3.1415));
+        testLength(Val.get(new Val[]{Val.get("multi"), Val.get("valued")}));
+        testLength(Val.get(new Val[]{}));
+        testLength(Val.get(new byte[10]));
+        testLength(Val.get(PropertyType.DATE, "2001-01-02"));
+        testLength(Val.get(PropertyType.DECIMAL, "10.00"));
+        testLength(Val.get(PropertyType.NAME, "xyz"));
+        testLength(Val.get(PropertyType.PATH, ""));
+        testLength(Val.get(PropertyType.PATH, "/xyz/abc"));
+        testLength(Val.get(PropertyType.REFERENCE, "abc:def"));
+        testLength(Val.get(PropertyType.WEAKREFERENCE, "abc:def"));
+        testLength(Val.get(PropertyType.BINARY, "0x1234"));
+        testLength(Val.get("long string with strange characters äöü \u1234"));
+        testLength(Val.get(new byte[1024]));
+        testLength(Val.get(new byte[1024 * 1024]));
+        testLength(true, Val.get(new Val[]{Val.get("Hello World 1"), Val.get("Hello World 2"), Val.get("Hello World 3")}));
+        testLength(true, Val.get(new Val[]{Val.get("Hello World 1"), Val.get("Hello World 1"), Val.get("Hello World 1")}));
+    }
+
+    static void testLength(Val v) {
+        testLength(false, v);
+    }
+
+    static void testLength(boolean allowSmaller, Val v) {
+        Bundle bundle = Bundle.create(512);
+        int len = bundle.writeVal(v).length();
+        // System.out.println("length: " + len + ": " + v);
+        bundle.reset();
+        Val v2 = bundle.readVal();
+        if (allowSmaller) {
+            if (len > bundle.getValLen(v)) {
+                throw new AssertionError();
+            }
+        } else {
+            if (len != bundle.getValLen(v)) {
+                throw new AssertionError();
+            }
+        }
+        if (v2.hashCode() != v.hashCode() || !v2.equals(v)) {
+            throw new AssertionError();
+        }
+    }
+
+}
+

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestConcurrentWrite.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,92 @@
+/*
+ * 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.j3;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+public class TestConcurrentWrite extends TestBase {
+
+   private String parentUUID;
+   private boolean stop;
+
+   public void test() throws Exception {
+
+       Node n = session.getRootNode().addNode("testParent");
+       parentUUID = n.getIdentifier();
+
+       Node node = session.getNodeByIdentifier(parentUUID);
+       node.addNode(UUID.randomUUID().toString());
+       session.save();
+
+       Session s2 = openSession();
+       Node n2 = s2.getNodeByIdentifier(parentUUID);
+       assertEquals("testParent", n2.getName());
+       s2.logout();
+
+   }
+
+   public void tearDown() throws Exception {
+       session.save();
+       session.logout();
+   }
+
+
+
+   public void testConcurrency() throws Exception {
+       int threadCount = 20;
+       final List<Exception> exceptions = new ArrayList<Exception>();
+       final CountDownLatch latch = new CountDownLatch(threadCount);
+       for (int i = 0; i < threadCount; i++) {
+           Thread thread = new Thread() {
+               public void run() {
+                   try {
+                       while (stop) {
+                           Session session = openSession();
+                           try {
+                               Node node = session.getNodeByIdentifier(parentUUID);
+                               node.addNode(UUID.randomUUID().toString());
+                               session.save();
+                           } finally {
+                               session.logout();
+                           }
+                       }
+                   } catch (RepositoryException e) {
+                       exceptions.add(e);
+                       stop = true;
+                   }
+                   latch.countDown();
+               }
+
+           };
+           thread.start();
+       }
+       latch.await(10, TimeUnit.SECONDS);
+       stop = true;
+       for (Exception e : exceptions) {
+           e.printStackTrace();
+       }
+       assertEquals(0, exceptions.size());
+   }
+
+}
\ No newline at end of file

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestNextConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestNextConfiguration.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestNextConfiguration.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestNextConfiguration.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,9 @@
+package org.apache.jackrabbit.j3;
+
+public class TestNextConfiguration extends TestBase {
+
+    public void testChange() {
+        configurationId++;
+    }
+
+}

Added: jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java?rev=922398&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java (added)
+++ jackrabbit/sandbox/jackrabbit-j3/src/test/java/org/apache/jackrabbit/j3/TestSimple.java Fri Mar 12 19:13:39 2010
@@ -0,0 +1,47 @@
+/*
+ * 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.j3;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+public class TestSimple extends TestBase {
+
+    public void test() throws Exception {
+
+        Session session = openSession();
+        Node root = session.getRootNode();
+        if (root.hasNode("test")) {
+            root.getNode("test").remove();
+            session.save();
+        }
+        Node test = root.addNode("test");
+        test.setProperty("name", "Hello");
+        session.save();
+        assertEquals("Hello", test.getProperty("name").getValue().getString());
+
+        Session session2 = openSession();
+        Node root2 = session2.getRootNode();
+        Node test2 = root2.getNode("test");
+        assertEquals("Hello", test2.getProperty("name").getValue().getString());
+        assertEquals("/test", test.getPath());
+        assertEquals("/test", test2.getPath());
+        session2.logout();
+        session.logout();
+
+    }
+}



Mime
View raw message