Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 89600 invoked from network); 12 Mar 2010 19:14:45 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 12 Mar 2010 19:14:45 -0000 Received: (qmail 9756 invoked by uid 500); 12 Mar 2010 19:14:08 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 9729 invoked by uid 500); 12 Mar 2010 19:14:08 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 9722 invoked by uid 99); 12 Mar 2010 19:14:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 12 Mar 2010 19:14:07 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 12 Mar 2010 19:14:01 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 5D0D823889B3; Fri, 12 Mar 2010 19:13:41 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 -0000 To: commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100312191341.5D0D823889B3@eris.apache.org> 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= 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 { + + 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 INDEX_MAP = new HashMap(); + + 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 prepared = new HashMap(); + 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 content = new HashMap(); + 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 content; + + MemStorageSession(MemStorage storage, HashMap 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 Test suite that executes all tests inside this + * package. + * + * @return a Test 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 parameters = new HashMap(); + 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 exceptions = new ArrayList(); + 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(); + + } +}