Skip to content

Commit

Permalink
Add MongoDB ObjectId and Timestamp types.
Browse files Browse the repository at this point in the history
 - Create simple interfaces for ObjectId and Timestamp.
 - Provide simple implementations for both interface.
 - Register new reader, writer and predicate objects for them.
 - Add simple tests for the implementations.
  • Loading branch information
kohanyirobert committed Jan 22, 2012
1 parent 5c65959 commit a94c000
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 2 deletions.
83 changes: 83 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/BasicObjectId.java
@@ -0,0 +1,83 @@
package com.github.kohanyirobert.ebson;

import com.google.common.base.Objects;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.xml.bind.DatatypeConverter;

final class BasicObjectId implements ObjectId {

private static final int TIME_LENGTH = 4;
private static final int MACHINE_ID_LENGTH = 3;
private static final int PROCESS_ID_LENGTH = 2;
private static final int INCREMENT_LENGTH = 3;
private static final int OBJECT_ID_LENGTH =
TIME_LENGTH + MACHINE_ID_LENGTH + PROCESS_ID_LENGTH + INCREMENT_LENGTH;

private final ByteBuffer time;
private final ByteBuffer machineId;
private final ByteBuffer processId;
private final ByteBuffer increment;

private final ByteBuffer objectId = ByteBuffer.allocate(OBJECT_ID_LENGTH).order(ByteOrder.BIG_ENDIAN);

BasicObjectId(ByteBuffer buffer) {
int oldLimit = buffer.limit();

buffer.limit(buffer.position() + OBJECT_ID_LENGTH);
objectId.put(buffer).flip();

assert buffer.limit() == oldLimit;

time = ByteBuffer.wrap(objectId.array(), 0, TIME_LENGTH).order(ByteOrder.BIG_ENDIAN);
machineId = ByteBuffer.wrap(objectId.array(), TIME_LENGTH, MACHINE_ID_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
processId = ByteBuffer.wrap(objectId.array(), MACHINE_ID_LENGTH, PROCESS_ID_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
increment = ByteBuffer.wrap(objectId.array(), PROCESS_ID_LENGTH, INCREMENT_LENGTH).order(ByteOrder.BIG_ENDIAN);
}

@Override
public ByteBuffer getObjectId() {
return objectId.asReadOnlyBuffer();
}

@Override
public ByteBuffer getTime() {
return time.asReadOnlyBuffer();
}

@Override
public ByteBuffer getMachineId() {
return machineId.asReadOnlyBuffer();
}

@Override
public ByteBuffer getProcessId() {
return processId.asReadOnlyBuffer();
}

@Override
public ByteBuffer getIncrement() {
return increment.asReadOnlyBuffer();
}

@Override
public int hashCode() {
return Objects.hashCode(objectId);
}

@Override
public boolean equals(Object object) {
if (object instanceof ObjectId) {
ObjectId other = (ObjectId) object;
return objectId.equals(other.getObjectId());
}
return false;
}

@Override
public String toString() {
return DatatypeConverter.printHexBinary(objectId.array()).toLowerCase();
}
}
66 changes: 66 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/BasicTimestamp.java
@@ -0,0 +1,66 @@
package com.github.kohanyirobert.ebson;

import com.google.common.base.Objects;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.xml.bind.DatatypeConverter;

final class BasicTimestamp implements Timestamp {

private static final int TIME_LENGTH = 4;
private static final int INCREMENT_LENGTH = 4;
private static final int TIMESTAMP_LENGTH = TIME_LENGTH + INCREMENT_LENGTH;

private final ByteBuffer time;
private final ByteBuffer increment;

private final ByteBuffer timestamp = ByteBuffer.allocate(TIMESTAMP_LENGTH).order(ByteOrder.LITTLE_ENDIAN);

BasicTimestamp(ByteBuffer buffer) {
int oldLimit = buffer.limit();

buffer.limit(buffer.position() + TIMESTAMP_LENGTH);
timestamp.put(buffer).flip();

assert buffer.limit() == oldLimit;

time = ByteBuffer.wrap(timestamp.array(), 0, TIME_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
increment = ByteBuffer.wrap(timestamp.array(), INCREMENT_LENGTH, TIME_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
}

@Override
public ByteBuffer getTimestamp() {
return timestamp.asReadOnlyBuffer();
}

@Override
public ByteBuffer getTime() {
return time.asReadOnlyBuffer();
}

@Override
public ByteBuffer getIncrement() {
return increment.asReadOnlyBuffer();
}

@Override
public int hashCode() {
return Objects.hashCode(timestamp);
}

@Override
public boolean equals(Object object) {
if (object instanceof Timestamp) {
Timestamp other = (Timestamp) object;
return timestamp.equals(other.getTimestamp());
}
return false;
}

@Override
public String toString() {
return DatatypeConverter.printHexBinary(timestamp.array()).toLowerCase();
}
}
6 changes: 4 additions & 2 deletions src/main/java/com/github/kohanyirobert/ebson/BsonObject.java
Expand Up @@ -63,7 +63,8 @@ public enum BsonObject {
* <b>Note:</b> special <a href="http://mongodb.org">MongoDB</a> related type.
* </p>
*/
OBJECT_ID(BsonBytes.OBJECT_ID),
OBJECT_ID(BsonBytes.OBJECT_ID, DefaultPredicate.OBJECT_ID,
DefaultReader.OBJECT_ID, DefaultWriter.OBJECT_ID),

/**
* Boolean.
Expand Down Expand Up @@ -138,7 +139,8 @@ public enum BsonObject {
* sharding.
* </p>
*/
TIMESTAMP(BsonBytes.TIMESTAMP),
TIMESTAMP(BsonBytes.TIMESTAMP, DefaultPredicate.TIMESTAMP,
DefaultReader.TIMESTAMP, DefaultWriter.TIMESTAMP),

/**
* 64-bit signed integer.
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/DefaultPredicate.java
Expand Up @@ -69,6 +69,16 @@ public boolean apply(Class<?> input) {
}
},

OBJECT_ID {

@Override
public boolean apply(Class<?> input) {
return input == null
? false
: ObjectId.class.isAssignableFrom(input);
}
},

BOOLEAN {

@Override
Expand Down Expand Up @@ -117,6 +127,16 @@ public boolean apply(Class<?> input) {
}
},

TIMESTAMP {

@Override
public boolean apply(Class<?> input) {
return input == null
? false
: Timestamp.class.isAssignableFrom(input);
}
},

INT64 {

@Override
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/DefaultReader.java
Expand Up @@ -108,6 +108,14 @@ public Object checkedReadFrom(ByteBuffer buffer) {
}
},

OBJECT_ID {

@Override
Object checkedReadFrom(ByteBuffer buffer) {
return new BasicObjectId(buffer);
}
},

BOOLEAN {

@Override
Expand Down Expand Up @@ -180,6 +188,14 @@ public Object checkedReadFrom(ByteBuffer buffer) {
}
},

TIMESTAMP {

@Override
Object checkedReadFrom(ByteBuffer buffer) {
return new BasicTimestamp(buffer);
}
},

INT64 {

@Override
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/DefaultWriter.java
Expand Up @@ -104,6 +104,14 @@ public void writeTo(ByteBuffer buffer, Object reference) {
}
},

OBJECT_ID {

@Override
public void writeTo(ByteBuffer buffer, Object reference) {
buffer.put(((ObjectId) reference).getObjectId());
}
},

BOOLEAN {

@Override
Expand Down Expand Up @@ -169,6 +177,14 @@ public void writeTo(ByteBuffer buffer, Object reference) {
}
},

TIMESTAMP {

@Override
public void writeTo(ByteBuffer buffer, Object reference) {
buffer.put(((Timestamp) reference).getTimestamp());
}
},

INT64 {

@Override
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/ObjectId.java
@@ -0,0 +1,17 @@
package com.github.kohanyirobert.ebson;

import java.nio.ByteBuffer;

// @checkstyle:off .
public interface ObjectId {

ByteBuffer getObjectId();

ByteBuffer getTime();

ByteBuffer getMachineId();

ByteBuffer getProcessId();

ByteBuffer getIncrement();
}
13 changes: 13 additions & 0 deletions src/main/java/com/github/kohanyirobert/ebson/Timestamp.java
@@ -0,0 +1,13 @@
package com.github.kohanyirobert.ebson;

import java.nio.ByteBuffer;

// @checkstyle:off .
public interface Timestamp {

ByteBuffer getTimestamp();

ByteBuffer getTime();

ByteBuffer getIncrement();
}
@@ -0,0 +1,32 @@
package com.github.kohanyirobert.ebson;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Random;

public final class DefaultObjectIdReaderWriterTest extends AbstractReaderWriterTest {

private static final ThreadLocal<ByteBuffer> RANDOM_OBJECT_ID = new ThreadLocal<ByteBuffer>() {

@Override
protected ByteBuffer initialValue() {
// @checkstyle:off MagicNumber
byte[] bytes = new byte[12];
new Random().nextBytes(bytes);
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
}
};

public DefaultObjectIdReaderWriterTest() {
super(DefaultReader.OBJECT_ID, DefaultWriter.OBJECT_ID);
}

@Test
public void randomObjectId() {
assertEquals(writeTo(new BasicObjectId(RANDOM_OBJECT_ID.get())), readFrom());
}
}
@@ -0,0 +1,32 @@
package com.github.kohanyirobert.ebson;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Random;

public final class DefaultTimestampReaderWriterTest extends AbstractReaderWriterTest {

private static final ThreadLocal<ByteBuffer> RANDOM_TIMESTAMP = new ThreadLocal<ByteBuffer>() {

@Override
protected ByteBuffer initialValue() {
// @checkstyle:off MagicNumber
byte[] bytes = new byte[8];
new Random().nextBytes(bytes);
return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
}
};

public DefaultTimestampReaderWriterTest() {
super(DefaultReader.TIMESTAMP, DefaultWriter.TIMESTAMP);
}

@Test
public void randomTimestamp() {
assertEquals(writeTo(new BasicTimestamp(RANDOM_TIMESTAMP.get())), readFrom());
}
}

0 comments on commit a94c000

Please sign in to comment.