#21
authorVyacheslav Tyutyunkov <tyutyunkov@gmail.com>
Wed, 27 Mar 2013 07:20:31 +0000 (14:20 +0700)
committerVyacheslav Tyutyunkov <tyutyunkov@gmail.com>
Wed, 27 Mar 2013 07:20:31 +0000 (14:20 +0700)
17 files changed:
jejdb/Makefile
jejdb/Makefile.in
jejdb/lib/bson.jar [deleted file]
jejdb/lib/mongo.jar [deleted file]
jejdb/src/cpp/jejdb.c
jejdb/src/java/org/ejdb/bson/BSON.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/BSONDecoder.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/BSONEncoder.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/BSONObject.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/io/OutputBuffer.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/types/ObjectId.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/bson/util/RegexFlag.java [new file with mode: 0644]
jejdb/src/java/org/ejdb/driver/EJDB.java
jejdb/src/java/org/ejdb/driver/EJDBCollection.java
jejdb/src/java/org/ejdb/driver/EJDBQuery.java
jejdb/src/java/org/ejdb/driver/EJDBResultSet.java
jejdb/src/test/org/ejdb/driver/test/EJDBTest.java

index b26d9a0..d1466d0 100644 (file)
@@ -44,6 +44,8 @@ all: $(LIBRARYFILES) jejdb tests
        @printf '# Ready to install.\n'
        @printf '#================================================================\n'
 
+compile-native : $(LIBRARYFILES)
+
 jejdb:
        ant build
 
index b533505..6e2a89e 100644 (file)
@@ -44,6 +44,8 @@ all: $(LIBRARYFILES) jejdb tests
        @printf '# Ready to install.\n'
        @printf '#================================================================\n'
 
+compile-native : $(LIBRARYFILES)
+
 jejdb:
        ant build
 
diff --git a/jejdb/lib/bson.jar b/jejdb/lib/bson.jar
deleted file mode 100644 (file)
index e735a4b..0000000
Binary files a/jejdb/lib/bson.jar and /dev/null differ
diff --git a/jejdb/lib/mongo.jar b/jejdb/lib/mongo.jar
deleted file mode 100644 (file)
index 717d0a5..0000000
Binary files a/jejdb/lib/mongo.jar and /dev/null differ
index d899177..f3dbb6d 100755 (executable)
@@ -93,8 +93,8 @@ static void fill_ejdb_collopts(JNIEnv *env, jobject obj, EJCOLLOPTS *ejcopts) {
 };
 
 static bson *encode_bson(JNIEnv *env, jobject jbson, bson *out) {
-       jclass jBSONClazz = (*env)->FindClass(env, "org/bson/BSON");
-       jmethodID encodeMethodID = (*env)->GetStaticMethodID(env, jBSONClazz, "encode", "(Lorg/bson/BSONObject;)[B");
+       jclass jBSONClazz = (*env)->FindClass(env, "org/ejdb/bson/BSON");
+       jmethodID encodeMethodID = (*env)->GetStaticMethodID(env, jBSONClazz, "encode", "(Lorg/ejdb/bson/BSONObject;)[B");
 
        jbyteArray bobjdata = (*env)->CallStaticObjectMethod(env, jBSONClazz, encodeMethodID, jbson);
        jbyte *bdata = (*env)->GetByteArrayElements(env, bobjdata, NULL);
@@ -111,8 +111,8 @@ static bson *encode_bson(JNIEnv *env, jobject jbson, bson *out) {
 };
 
 static jobject decode_bson_from_buffer(JNIEnv *env, const void *buffer, jsize size) {
-       jclass jBSONClazz = (*env)->FindClass(env, "org/bson/BSON");
-       jmethodID decodeMethodID = (*env)->GetStaticMethodID(env, jBSONClazz, "decode", "([B)Lorg/bson/BSONObject;");
+       jclass jBSONClazz = (*env)->FindClass(env, "org/ejdb/bson/BSON");
+       jmethodID decodeMethodID = (*env)->GetStaticMethodID(env, jBSONClazz, "decode", "([B)Lorg/ejdb/bson/BSONObject;");
 
        jbyteArray jbsdata = (*env)->NewByteArray(env, size);
        (*env)->SetByteArrayRegion(env, jbsdata, 0, size, (jbyte*)buffer);
@@ -471,7 +471,7 @@ JNIEXPORT void JNICALL Java_org_ejdb_driver_EJDBCollection_updateMeta (JNIEnv *e
 /*
  * Class:     org_ejdb_driver_EJDBCollection
  * Method:    load
- * Signature: (Lorg/bson/types/ObjectId;)Lorg/bson/BSONObject;
+ * Signature: (Lorg/ejdb/bson/types/ObjectId;)Lorg/ejdb/bson/BSONObject;
  */
 JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_load (JNIEnv *env, jobject obj, jobject joid) {
        EJDB* db = get_ejdb_from_object(env, obj);              
@@ -490,7 +490,7 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_load (JNIEnv *env,
                return NULL;
        }
 
-       jclass jObjectIdClazz = (*env)->FindClass(env, "org/bson/types/ObjectId");
+       jclass jObjectIdClazz = (*env)->FindClass(env, "org/ejdb/bson/types/ObjectId");
        jmethodID encodeMethodID = (*env)->GetMethodID(env, jObjectIdClazz, "toByteArray", "()[B");
        jbyteArray joiddata = (*env)->CallObjectMethod(env, joid, encodeMethodID);
        bson_oid_t *oid = (bson_oid_t*)(*env)->GetByteArrayElements(env, joiddata, NULL);
@@ -511,7 +511,7 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_load (JNIEnv *env,
 /*
  * Class:     org_ejdb_driver_EJDBCollection
  * Method:    save
- * Signature: (Lorg/bson/BSONObject;)Lorg/bson/types/ObjectId;
+ * Signature: (Lorg/ejdb/bson/BSONObject;)Lorg/ejdb/bson/types/ObjectId;
  */
 JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_save (JNIEnv *env, jobject obj, jobject jdata) {
     if (NULL == jdata) {
@@ -547,7 +547,7 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_save (JNIEnv *env,
                return NULL;
        }
 
-       jclass jObjectIdClazz = (*env)->FindClass(env, "org/bson/types/ObjectId");
+       jclass jObjectIdClazz = (*env)->FindClass(env, "org/ejdb/bson/types/ObjectId");
        jmethodID initMethodID = (*env)->GetMethodID(env, jObjectIdClazz, "<init>", "([B)V");
 
        jbyteArray joiddata = (*env)->NewByteArray(env, sizeof(oid));
@@ -556,6 +556,14 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_save (JNIEnv *env,
 
        (*env)->DeleteLocalRef(env, joiddata);
 
+       jclass clazz = (*env)->GetObjectClass(env, jdata);
+       jmethodID putMethodID = (*env)->GetMethodID(env, clazz, "put", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+
+       jstring oidField = (*env)->NewStringUTF(env, "_id");
+       (*env)->CallObjectMethod(env, jdata, putMethodID, oidField, result);
+
+       (*env)->DeleteLocalRef(env, oidField);
+
        update_coll_meta(env, obj, coll);
 
        return result;
@@ -564,7 +572,7 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBCollection_save (JNIEnv *env,
 /*
  * Class:     org_ejdb_driver_EJDBCollection
  * Method:    remove
- * Signature: (Lorg/bson/types/ObjectId;)V
+ * Signature: (Lorg/ejdb/bson/types/ObjectId;)V
  */
 JNIEXPORT void JNICALL Java_org_ejdb_driver_EJDBCollection_remove (JNIEnv *env, jobject obj, jobject joid) {
        EJDB* db = get_ejdb_from_object(env, obj);
@@ -582,7 +590,7 @@ JNIEXPORT void JNICALL Java_org_ejdb_driver_EJDBCollection_remove (JNIEnv *env,
                return;
        }
 
-       jclass jObjectIdClazz = (*env)->FindClass(env, "org/bson/types/ObjectId");
+       jclass jObjectIdClazz = (*env)->FindClass(env, "org/ejdb/bson/types/ObjectId");
        jmethodID encodeMethodID = (*env)->GetMethodID(env, jObjectIdClazz, "toByteArray", "()[B");
        jbyteArray joiddata = (*env)->CallObjectMethod(env, joid, encodeMethodID);
        bson_oid_t *oid = (bson_oid_t*)(*env)->GetByteArrayElements(env, joiddata, NULL);
@@ -631,7 +639,7 @@ JNIEXPORT void JNICALL Java_org_ejdb_driver_EJDBCollection_setIndex (JNIEnv *env
 /*
  * Class:     org_ejdb_driver_EJDBQuery
  * Method:    execute
- * Signature: (Lorg/bson/BSONObject;[Lorg/bson/BSONObject;Lorg/bson/BSONObject;ILjava/io/OutputStream;)Lorg/ejdb/driver/EJDBQuery$QResult;
+ * Signature: (Lorg/ejdb/bson/BSONObject;[Lorg/ejdb/bson/BSONObject;Lorg/ejdb/bson/BSONObject;ILjava/io/OutputStream;)Lorg/ejdb/driver/EJDBQuery$QResult;
  */
 JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBQuery_execute (JNIEnv *env, jobject obj, jobject qobj, jobjectArray qorarrobj, jobject hobj, jint flags, jobject logstream) {
        jclass jQResultClazz = (*env)->FindClass(env, "org/ejdb/driver/EJDBQuery$QResult");
@@ -655,9 +663,8 @@ JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBQuery_execute (JNIEnv *env, j
 
        qbson = encode_bson(env, qobj, NULL);
 
-       // todo: check query bson
        if (!qbson) {
-               //
+               // TODO: ?
                goto finish;
        }
 
@@ -762,7 +769,7 @@ finish:
 /*
 * Class:     org_ejdb_driver_EJDBResultSet
 * Method:    get
-* Signature: (I)Lorg/bson/BSONObject;
+* Signature: (I)Lorg/ejdb/bson/BSONObject;
 */
 JNIEXPORT jobject JNICALL Java_org_ejdb_driver_EJDBResultSet_get (JNIEnv *env, jobject obj, jint indx) {
        TCLIST *rs = get_rs_from_object(env, obj);
diff --git a/jejdb/src/java/org/ejdb/bson/BSON.java b/jejdb/src/java/org/ejdb/bson/BSON.java
new file mode 100644 (file)
index 0000000..9184f1d
--- /dev/null
@@ -0,0 +1,34 @@
+package org.ejdb.bson;
+
+import java.io.OutputStream;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public final class BSON {
+
+    public static final byte NULL = (byte) 0x0A;
+    public static final byte INT = (byte) 0x10;
+    public static final byte LONG = (byte) 0x11;
+    public static final byte DOUBLE = (byte) 0x01;
+    public static final byte STRING = (byte) 0x02;
+    public static final byte BOOLEAN = (byte) 0x08;
+    public static final byte OBJECT_ID = (byte) 0x07;
+    public static final byte OBJECT = (byte) 0x03;
+    public static final byte BINARY = (byte) 0x05;
+    public static final byte ARRAY = (byte) 0x04;
+    public static final byte DATE = (byte) 0x09;
+    public static final byte REGEX = (byte) 0x0B;
+
+    private BSON() {
+    }
+
+    public static byte[] encode(BSONObject obj){
+        return new BSONEncoder().encode(obj);
+    }
+
+    public static BSONObject decode(byte[] data) {
+        return new BSONDecoder().decode(data);
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/BSONDecoder.java b/jejdb/src/java/org/ejdb/bson/BSONDecoder.java
new file mode 100644 (file)
index 0000000..9919b77
--- /dev/null
@@ -0,0 +1,38 @@
+package org.ejdb.bson;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public class BSONDecoder {
+
+    public BSONObject decode(byte[] data) {
+        return new BSONObject();
+    }
+
+    public int readInt(byte[] data) {
+        return readInt(data, 0);
+    }
+
+    public int readInt(byte[] data, int offset) {
+        int result = 0;
+        for (int i = 0; i < 4; ++i) {
+            result |= (0xFF & data[offset + i]) << (i * 8);
+        }
+
+        return result;
+    }
+
+    public long readLong(byte[] data) {
+        return readLong(data, 0);
+    }
+
+    public long readLong(byte[] data, int offset) {
+        long result = 0;
+        for (int i = 0; i < 8; ++i) {
+            result |= (0xFFL & data[offset + i]) << (i * 8);
+        }
+
+        return result;
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/BSONEncoder.java b/jejdb/src/java/org/ejdb/bson/BSONEncoder.java
new file mode 100644 (file)
index 0000000..42844f9
--- /dev/null
@@ -0,0 +1,192 @@
+package org.ejdb.bson;
+
+import org.ejdb.bson.io.OutputBuffer;
+import org.ejdb.bson.types.ObjectId;
+import org.ejdb.bson.util.RegexFlag;
+
+import java.lang.reflect.Array;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public class BSONEncoder {
+
+    private OutputBuffer output;
+
+    public byte[] encode(BSONObject object) throws IllegalStateException {
+        if (isBusy()) {
+            throw new IllegalStateException("other encoding in process");
+        }
+
+        if (object == null) {
+            throw new IllegalArgumentException("can not serialize null document object");
+        }
+
+        output = new OutputBuffer();
+        this.handleObject(object);
+        byte[] result = output.getResult();
+        output = null;
+
+        return result;
+    }
+
+    public boolean isBusy() {
+        return output != null;
+    }
+
+    protected void handleObject(BSONObject object) {
+        int start = output.getPosition();
+
+        output.writeInt(0);
+
+        for (String field : object.keySet()) {
+            writeField(field, object.get(field));
+        }
+
+        int end = output.getPosition();
+
+        output.writeIntAt(start, end - start);
+    }
+
+    protected void writeFieldSpec(byte type, String name) {
+        output.write(type);
+        output.writeString(name);
+    }
+
+    protected void writeField(String name, Object value) {
+        if (null == value) {
+            writeNull(name);
+        } else if (value instanceof Number) {
+            writeNumber(name, (Number) value);
+        } else if (value instanceof String) {
+            writeString(name, (String) value);
+        } else if (value instanceof Character) {
+            writeString(name, value.toString());
+        } else if (value instanceof Boolean) {
+            writeBoolean(name, (Boolean) value);
+        } else if (value instanceof ObjectId) {
+            writeObjectId(name, (ObjectId) value);
+        } else if (value instanceof BSONObject) {
+            writeObject(name, (BSONObject) value);
+        } else if (value instanceof Map) {
+            writeObject(name, new BSONObject((Map) value));
+        } else if (value instanceof byte[]) {
+            writeBinary(name, (byte[]) value);
+        } else if (value instanceof Iterable) {
+            writeArray(name, ((Iterable) value).iterator());
+        } else if (value.getClass().isArray()) {
+            writeArray(name, wrapArrayIterator(value));
+        } else if (value instanceof Date) {
+            writeDate(name, (Date) value);
+        } else if (value instanceof Pattern) {
+            writeRegex(name, (Pattern) value);
+        } else {
+            throw new IllegalArgumentException("can not serialize object: " + value.getClass().getName());
+        }
+    }
+
+    protected void writeNull(String name) {
+        writeFieldSpec(BSON.NULL, name);
+    }
+
+    protected void writeNumber(String name, Number value) {
+        if (value instanceof Integer || value instanceof Short || value instanceof Byte || value instanceof AtomicInteger) {
+            writeFieldSpec(BSON.INT, name);
+            output.writeInt(value.intValue());
+        } else if (value instanceof Long || value instanceof AtomicLong) {
+            writeFieldSpec(BSON.LONG, name);
+            output.writeLong(value.longValue());
+        } else if (value instanceof Double || value instanceof Float) {
+            writeFieldSpec(BSON.DOUBLE, name);
+            output.writeDouble(value.doubleValue());
+        } else {
+            throw new IllegalArgumentException("can not serialize object: " + value.getClass().getName());
+        }
+    }
+
+    protected void writeString(String name, String value) {
+        writeFieldSpec(BSON.STRING, name);
+
+        int sp = output.getPosition();
+        output.writeInt(0);
+        int length = output.writeString(value);
+        output.writeIntAt(sp, length);
+    }
+
+    protected void writeBoolean(String name, Boolean value) {
+        writeFieldSpec(BSON.BOOLEAN, name);
+        output.write((byte) (value ? 0x01 : 0x00));
+    }
+
+    protected void writeObjectId(String name, ObjectId value) {
+        writeFieldSpec(BSON.OBJECT_ID, name);
+        output.write(value.toByteArray());
+    }
+
+    protected void writeObject(String name, BSONObject value) {
+        writeFieldSpec(BSON.OBJECT, name);
+        handleObject(value);
+    }
+
+    protected void writeBinary(String name, byte[] value) {
+        writeFieldSpec(BSON.BINARY, name);
+        output.writeInt(value.length);
+        output.write((byte) 0x00);
+        output.write(value);
+    }
+
+    protected void writeArray(String name, Iterator<Object> value) {
+        writeFieldSpec(BSON.ARRAY, name);
+
+        int sp = output.getPosition();
+        output.writeInt(0);
+        int i = 0;
+        while (value.hasNext()) {
+            writeField(String.valueOf(i), value.next());
+            ++i;
+        }
+        output.writeIntAt(sp, output.getPosition() - sp);
+    }
+
+    protected void writeDate(String name, Date value) {
+        writeFieldSpec(BSON.DATE, name);
+        output.writeLong(value.getTime());
+    }
+
+    protected void writeRegex(String name, Pattern value) {
+        writeFieldSpec(BSON.REGEX, name);
+        output.writeString(value.pattern());
+        output.writeString(RegexFlag.regexFlagsToString(value.flags()));
+    }
+
+    protected Iterator<Object> wrapArrayIterator(final Object array) {
+        final int size = Array.getLength(array);
+        return new Iterator<Object>() {
+            private int position;
+
+            public boolean hasNext() {
+                return position < size;
+            }
+
+            public Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                return Array.get(array, position++);
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/BSONObject.java b/jejdb/src/java/org/ejdb/bson/BSONObject.java
new file mode 100644 (file)
index 0000000..f5df116
--- /dev/null
@@ -0,0 +1,91 @@
+package org.ejdb.bson;
+
+import org.ejdb.bson.types.ObjectId;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public class BSONObject {
+    private static final String ID_KEY = "_id";
+
+    private Map<String, Object> data;
+
+    {
+        data = new HashMap<String, Object>();
+    }
+
+    public BSONObject() {
+    }
+
+    public BSONObject(ObjectId oid) {
+        this(ID_KEY, oid);
+    }
+
+    public BSONObject(String key, Object value) {
+        this.put(key, value);
+    }
+
+    public BSONObject(Map<String, Object> data) {
+        this.putAll(data);
+    }
+
+    public Object put(String key, Object value) {
+        if (ID_KEY.equals(key)) {
+            if (value instanceof ObjectId) {
+                // noop
+            } else if (value instanceof byte[]) {
+                value = new ObjectId((byte[]) value);
+            } else if (value instanceof String) {
+                value = new ObjectId((String) value);
+            } else {
+                throw new IllegalArgumentException("expected ObjectId");
+            }
+        }
+
+        return data.put(key, value);
+    }
+
+    public BSONObject append(String key, Object value) {
+        this.put(key, value);
+
+        return this;
+    }
+
+    public void putAll(Map<String, Object> values) {
+        for (Map.Entry<String, Object> entry : values.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    public void putAll(BSONObject object) {
+        this.putAll(object.asMap());
+    }
+
+    public Map<String, Object> asMap() {
+        return new HashMap<String, Object>(data);
+    }
+
+    public Set<String> keySet() {
+        return new HashSet<String>(data.keySet());
+    }
+
+    public Object get(String key) {
+        return data.get(key);
+    }
+
+    public boolean containsField(String key) {
+        return data.containsKey(key);
+    }
+
+    @Override
+    public String toString() {
+        return data.toString();
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/io/OutputBuffer.java b/jejdb/src/java/org/ejdb/bson/io/OutputBuffer.java
new file mode 100644 (file)
index 0000000..2387a92
--- /dev/null
@@ -0,0 +1,112 @@
+package org.ejdb.bson.io;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public class OutputBuffer {
+    public static final int BUFFER_DEFAULT_LENGTH = 512;
+
+    private byte[] buffer;
+    private int position;
+    private int actualSize;
+
+    {
+        buffer = new byte[BUFFER_DEFAULT_LENGTH];
+        position = 0;
+        actualSize = 0;
+    }
+
+    public int getPosition() {
+        return position;
+    }
+
+    public void setPosition(int position) {
+        this.position = position;
+    }
+
+    public int getActualSize() {
+        return actualSize;
+    }
+
+    public byte[] getResult() {
+        byte[] result = new byte[getActualSize()];
+        System.arraycopy(buffer, 0, result, 0, getActualSize());
+        return result;
+    }
+
+    public void write(byte data) {
+        ensureLength(1);
+        buffer[position++] = data;
+        actualSize = Math.max(actualSize, position);
+    }
+
+    public void write(byte[] data) {
+        this.write(data, 0, data.length);
+    }
+
+    public void write(byte[] data, int offset, int length) {
+        ensureLength(length);
+        System.arraycopy(data, offset, buffer, position, length);
+        position += length;
+        actualSize = Math.max(actualSize, position);
+    }
+
+    public void writeIntAt(int position, int value) {
+        int save = getPosition();
+        setPosition(position);
+        writeInt(value);
+        setPosition(save);
+    }
+
+    public void writeInt(int value) {
+        this.write(new byte[]{
+                (byte) ((value >>> 0) & 0xFF),
+                (byte) ((value >>> 8) & 0xFF),
+                (byte) ((value >>> 16) & 0xFF),
+                (byte) ((value >>> 24) & 0xFF)
+        });
+    }
+
+    public void writeLong(long value) {
+        this.write(new byte[]{
+                (byte) ((value >>> 0) & 0xFF),
+                (byte) ((value >>> 8) & 0xFF),
+                (byte) ((value >>> 16) & 0xFF),
+                (byte) ((value >>> 24) & 0xFF),
+                (byte) ((value >>> 32) & 0xFF),
+                (byte) ((value >>> 40) & 0xFF),
+                (byte) ((value >>> 48) & 0xFF),
+                (byte) ((value >>> 56) & 0xFF),
+        });
+    }
+
+    public void writeDouble(double value) {
+        this.writeLong(Double.doubleToRawLongBits(value));
+    }
+
+    public int writeString(String value) {
+        int start = getPosition();
+        try {
+            this.write(value.getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        this.write((byte) 0x00);
+
+        return getPosition() - start;
+    }
+
+    protected void ensureLength(int need) {
+        if (need <= buffer.length - position) {
+            return;
+        }
+
+        int newSize = (int) Math.floor(((double) (need + position - buffer.length)) / BUFFER_DEFAULT_LENGTH) * BUFFER_DEFAULT_LENGTH;
+        byte[] newBuffer = new byte[newSize];
+        System.arraycopy(buffer, 0, newBuffer, 0, position);
+        buffer = newBuffer;
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/types/ObjectId.java b/jejdb/src/java/org/ejdb/bson/types/ObjectId.java
new file mode 100644 (file)
index 0000000..c8fcb40
--- /dev/null
@@ -0,0 +1,64 @@
+package org.ejdb.bson.types;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public class ObjectId {
+
+    private byte[] data;
+
+    public ObjectId(byte[] data) {
+        if (data == null || data.length != 12) {
+            throw new IllegalArgumentException("unexpected ObjectId data");
+        }
+
+        this.data = new byte[12];
+        System.arraycopy(data, 0, this.data, 0, 12);
+    }
+
+    public ObjectId(String value) {
+        if (!isValid(value)) {
+            throw new IllegalArgumentException("unexpected ObjectId data");
+        }
+
+        this.data = new byte[12];
+        for (int i = 0; i < 12; ++i) {
+            this.data[i] = Byte.parseByte(value.substring(i << 1, i << 1 + 2), 16);
+        }
+    }
+
+    public byte[] toByteArray() {
+        byte[] result = new byte[12];
+        System.arraycopy(data, 0, result, 0, 12);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder(34);
+        builder.append("ObjectId(");
+        for (byte b : data) {
+            builder.append(String.format("%02x", b));
+        }
+        builder.append(")");
+
+        return builder.toString();
+    }
+
+    public static boolean isValid(String value) {
+        if (value == null || value.length() != 24) {
+            return false;
+        }
+
+        value = value.toUpperCase();
+        for (int i = 0; i < value.length(); ++i) {
+            char c = value.charAt(i);
+            if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/jejdb/src/java/org/ejdb/bson/util/RegexFlag.java b/jejdb/src/java/org/ejdb/bson/util/RegexFlag.java
new file mode 100644 (file)
index 0000000..93baae2
--- /dev/null
@@ -0,0 +1,77 @@
+package org.ejdb.bson.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * @author Tyutyunkov Vyacheslav (tve@softmotions.com)
+ * @version $Id$
+ */
+public final class RegexFlag {
+    private static List<RegexFlag> regexFlags;
+    private static Map<Character, RegexFlag> characterToRegexFlagMap;
+
+    private int flag;
+    private char character;
+    private boolean supported;
+
+    private RegexFlag(int flag, char character, boolean supported) {
+        this.flag = flag;
+        this.character = character;
+        this.supported = supported;
+    }
+
+    public static String regexFlagsToString(int flags) {
+        StringBuilder result = new StringBuilder();
+        for (RegexFlag regexFlag : regexFlags) {
+            if ((flags & regexFlag.getFlag()) > 0 && regexFlag.isSupported()) {
+                result.append(regexFlag.getCharacter());
+            }
+        }
+
+        return result.toString();
+    }
+
+    public static void registerRegexFlag(int flag, char character, boolean supported) {
+        RegexFlag rf = new RegexFlag(flag, character, supported);
+        regexFlags.add(rf);
+        characterToRegexFlagMap.put(rf.getCharacter(), rf);
+    }
+
+    public int getFlag() {
+        return flag;
+    }
+
+    public char getCharacter() {
+        return character;
+    }
+
+    public boolean isSupported() {
+        return supported;
+    }
+
+    static {
+        RegexFlag.regexFlags = new ArrayList<RegexFlag>();
+        RegexFlag.characterToRegexFlagMap = new HashMap<Character, RegexFlag>();
+
+        RegexFlag.registerRegexFlag(Pattern.CASE_INSENSITIVE, 'i', true);
+        RegexFlag.registerRegexFlag(Pattern.MULTILINE, 'm', true);
+        RegexFlag.registerRegexFlag(Pattern.COMMENTS, 'x', true);
+        RegexFlag.registerRegexFlag(Pattern.DOTALL, 's', true);
+        RegexFlag.registerRegexFlag(Pattern.UNICODE_CASE, 'u', true);
+        RegexFlag.registerRegexFlag(Pattern.CANON_EQ, 'c', false);
+        RegexFlag.registerRegexFlag(Pattern.LITERAL, 't', false);
+        RegexFlag.registerRegexFlag(Pattern.UNIX_LINES, 'd', false);
+
+        Collections.sort(RegexFlag.regexFlags, new Comparator<RegexFlag>() {
+            public int compare(RegexFlag o1, RegexFlag o2) {
+                return o1.getCharacter() - o2.getCharacter();
+            }
+        });
+    }
+}
index cb5417d..176138e 100644 (file)
@@ -1,9 +1,5 @@
 package org.ejdb.driver;
 
-import com.sun.servicetag.SystemEnvironment;
-
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
index c1f860e..753673e 100644 (file)
@@ -1,7 +1,7 @@
 package org.ejdb.driver;
 
-import org.bson.BSONObject;
-import org.bson.types.ObjectId;
+import org.ejdb.bson.BSONObject;
+import org.ejdb.bson.types.ObjectId;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -339,21 +339,21 @@ public class EJDBCollection {
     }
 
     /**
-     * @see EJDBCollection#createQuery(org.bson.BSONObject, org.bson.BSONObject[], org.bson.BSONObject)
+     * @see EJDBCollection#createQuery(org.ejdb.bson.BSONObject, org.ejdb.bson.BSONObject[], org.ejdb.bson.BSONObject)
      */
     public EJDBQuery createQuery(BSONObject query) {
         return new EJDBQuery(this, query, null, null);
     }
 
     /**
-     * @see EJDBCollection#createQuery(org.bson.BSONObject, org.bson.BSONObject[], org.bson.BSONObject)
+     * @see EJDBCollection#createQuery(org.ejdb.bson.BSONObject, org.ejdb.bson.BSONObject[], org.ejdb.bson.BSONObject)
      */
     public EJDBQuery createQuery(BSONObject query, BSONObject[] qors) {
         return new EJDBQuery(this, query, qors, null);
     }
 
     /**
-     * @see EJDBCollection#createQuery(org.bson.BSONObject, org.bson.BSONObject[], org.bson.BSONObject)
+     * @see EJDBCollection#createQuery(org.ejdb.bson.BSONObject, org.ejdb.bson.BSONObject[], org.ejdb.bson.BSONObject)
      */
     public EJDBQuery createQuery(BSONObject query, BSONObject hints) {
         return new EJDBQuery(this, query, null, hints);
index 404a6ff..630b1b6 100644 (file)
@@ -1,7 +1,6 @@
 package org.ejdb.driver;
 
-import org.bson.BSONObject;
-import org.bson.BasicBSONObject;
+import org.ejdb.bson.BSONObject;
 
 import java.io.IOException;
 import java.io.OutputStream;
@@ -80,10 +79,10 @@ public class EJDBQuery {
      * Same as  {@link org.ejdb.driver.EJDBQuery#find()} but retrieves only one matching JSON object.
      */
     public BSONObject findOne(OutputStream log) throws EJDBException, IOException {
-        Map hintsMap = hints != null ? hints.toMap() : new HashMap();
+        Map<String, Object> hintsMap = hints != null ? hints.asMap() : new HashMap();
         hintsMap.put("$max", 1);
 
-        EJDBResultSet rs = this.execute(new BasicBSONObject(hintsMap), 0, null).getResultSet();
+        EJDBResultSet rs = this.execute(new BSONObject(hintsMap), 0, null).getResultSet();
         BSONObject result = rs.hasNext() ? rs.next() : null;
         rs.close();
 
index 624d642..f11bb8d 100644 (file)
@@ -1,6 +1,6 @@
 package org.ejdb.driver;
 
-import org.bson.BSONObject;
+import org.ejdb.bson.BSONObject;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
index 680b9f0..0c01d6d 100644 (file)
@@ -2,9 +2,8 @@ package org.ejdb.driver.test;
 
 import junit.framework.TestCase;
 
-import org.bson.BSONObject;
-import org.bson.BasicBSONObject;
-import org.bson.types.ObjectId;
+import org.ejdb.bson.BSONObject;
+import org.ejdb.bson.types.ObjectId;
 import org.ejdb.driver.EJDB;
 import org.ejdb.driver.EJDBCollection;
 import org.ejdb.driver.EJDBQuery;
@@ -55,7 +54,7 @@ public class EJDBTest extends TestCase {
         coll.ensureExists();
         assertTrue(coll.isExists());
 
-        BSONObject obj = new BasicBSONObject("test", "test").append("test2", 123);
+        BSONObject obj = new BSONObject("test", "test").append("test2", 123);
 
 
         ObjectId oid = coll.save(obj);
@@ -67,7 +66,7 @@ public class EJDBTest extends TestCase {
         assertEquals(obj.get("test"), lobj.get("test"));
         assertEquals(obj.get("test2"), lobj.get("test2"));
 
-        EJDBQuery query = coll.createQuery(new BasicBSONObject());
+        EJDBQuery query = coll.createQuery(new BSONObject());
         EJDBResultSet rs = query.find();
         assertEquals(rs.length(), 1);
         for (BSONObject r : rs) {
@@ -78,13 +77,13 @@ public class EJDBTest extends TestCase {
 
         assertEquals(lobj, query.findOne());
 
-        EJDBQuery query2 = db.getCollection("test2").createQuery(new BasicBSONObject());
+        EJDBQuery query2 = db.getCollection("test2").createQuery(new BSONObject());
         assertNull(query2.findOne());
 
         assertEquals(query.count(), 1);
         assertEquals(query2.count(), 0);
 
-        EJDBQuery query3 = coll.createQuery(new BasicBSONObject("test", "test"), new BasicBSONObject("$fields", new BasicBSONObject("test2", 0)));
+        EJDBQuery query3 = coll.createQuery(new BSONObject("test", "test"), new BSONObject("$fields", new BSONObject("test2", 0)));
         assertEquals(query3.count(), 1);
 
         rs = query3.find();
@@ -104,7 +103,7 @@ public class EJDBTest extends TestCase {
     public void testQueries() throws Exception {
         assertTrue(db.isOpen());
 
-        BSONObject obj1 = new BasicBSONObject("name", "Grenny")
+        BSONObject obj1 = new BSONObject("name", "Grenny")
                 .append("type", "African Grey")
                 .append("male", true)
                 .append("age", 1)
@@ -112,7 +111,7 @@ public class EJDBTest extends TestCase {
                 .append("likes", new String[]{"green color", "night", "toys"})
                 .append("extra1", null);
 
-        BSONObject obj2 = new BasicBSONObject("name", "Bounty")
+        BSONObject obj2 = new BSONObject("name", "Bounty")
                 .append("type", "Cockatoo")
                 .append("male", false)
                 .append("age", 15)
@@ -131,14 +130,14 @@ public class EJDBTest extends TestCase {
         BSONObject obj12 = parrots.load(ss.get(0));
         assertEquals(ss.get(0), obj12.get("_id"));
 
-        EJDBQuery query = parrots.createQuery(new BasicBSONObject());
+        EJDBQuery query = parrots.createQuery(new BSONObject());
         EJDBResultSet rs = query.find();
         assertEquals(rs.length(), 2);
         rs.close();
 
 
-        query = parrots.createQuery(new BasicBSONObject("name", Pattern.compile("(grenny|bounty)", Pattern.CASE_INSENSITIVE)),
-                                    new BasicBSONObject("$orderby", new BasicBSONObject("name", 1)));
+        query = parrots.createQuery(new BSONObject("name", Pattern.compile("(grenny|bounty)", Pattern.CASE_INSENSITIVE)),
+                                    new BSONObject("$orderby", new BSONObject("name", 1)));
 
         rs = query.find();
         assertEquals(rs.length(), 2);
@@ -147,17 +146,17 @@ public class EJDBTest extends TestCase {
         assertEquals(robj1.get("age"), 15);
         rs.close();
 
-        query = parrots.createQuery(new BasicBSONObject(),
-                                    new BSONObject[]{new BasicBSONObject("name", "Grenny"), new BasicBSONObject("name", "Bounty")},
-                                    new BasicBSONObject("$orderby", new BasicBSONObject("name", 1)));
+        query = parrots.createQuery(new BSONObject(),
+                                    new BSONObject[]{new BSONObject("name", "Grenny"), new BSONObject("name", "Bounty")},
+                                    new BSONObject("$orderby", new BSONObject("name", 1)));
 
         rs = query.find();
         assertEquals(rs.length(), 2);
         rs.close();
 
-        query = parrots.createQuery(new BasicBSONObject(),
-                                    new BSONObject[]{new BasicBSONObject("name", "Grenny")},
-                                    new BasicBSONObject("$orderby", new BasicBSONObject("name", 1)));
+        query = parrots.createQuery(new BSONObject(),
+                                    new BSONObject[]{new BSONObject("name", "Grenny")},
+                                    new BSONObject("$orderby", new BSONObject("name", 1)));
 
         assertEquals(query.count(), 1);
     }
@@ -165,15 +164,15 @@ public class EJDBTest extends TestCase {
     public void testIndexes() throws Exception {
         assertTrue(db.isOpen());
 
-        BSONObject sally = new BasicBSONObject("name", "Sally").append("mood", "Angry");
-        BSONObject molly = new BasicBSONObject("name", "Molly").append("mood", "Very angry").append("secret", null);
+        BSONObject sally = new BSONObject("name", "Sally").append("mood", "Angry");
+        BSONObject molly = new BSONObject("name", "Molly").append("mood", "Very angry").append("secret", null);
 
         EJDBCollection birds = db.getCollection("birds");
         birds.save(Arrays.asList(sally, molly));
 
         ByteArrayOutputStream log;
 
-        EJDBQuery query = birds.createQuery(new BasicBSONObject("name", "Molly"));
+        EJDBQuery query = birds.createQuery(new BSONObject("name", "Molly"));
 
         query.find(log = new ByteArrayOutputStream());
         assertTrue(log.toString().contains("RUN FULLSCAN"));
@@ -189,7 +188,7 @@ public class EJDBTest extends TestCase {
         assertTrue(db.isOpen());
 
         ObjectId boid;
-        BasicBSONObject bar = new BasicBSONObject("foo", "bar");
+        BSONObject bar = new BSONObject("foo", "bar");
 
         EJDBCollection bars = db.getCollection("bars");