/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.internal.handlers;
import com.db4o.*;
import com.db4o.ext.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
import com.db4o.internal.delete.*;
import com.db4o.internal.marshall.*;
import com.db4o.internal.slots.*;
import com.db4o.marshall.*;
import com.db4o.typehandlers.*;
/**
* @sharpen.ignore
* @exclude
*/
public abstract class ByteArrayRepresentableTypeHandler<T> implements ValueTypeHandler, VariableLengthTypeHandler, QueryableTypeHandler, IndexableTypeHandler {
public void defragment(DefragmentContext context) {
skip(context);
}
public void delete(DeleteContext context) throws Db4oIOException {
skip(context);
}
public Object read(ReadContext context) {
return unmarshall(context);
}
public void write(WriteContext context, Object obj) {
byte[] data = toByteArray((T)obj);
context.writeInt(data.length);
context.writeBytes(data);
}
public PreparedComparison<Object> prepareComparison(final Context context, Object obj) {
final T value = obj instanceof TransactionContext
? valueFrom(((TransactionContext)obj)._object, context)
: valueFrom(obj, context);
return new PreparedComparison<Object>() {
public int compareTo(Object other) {
if (other == null) {
return (value == null ? 0 : 1);
}
if(value == null) {
return -1;
}
return compare(value, valueFrom(other, context));
}
};
}
public boolean descendsIntoMembers() {
return false;
}
public void defragIndexEntry(DefragmentContextImpl context) {
context.copyAddress();
context.incrementIntSize();
}
public int linkLength() {
return Const4.INDIRECTION_LENGTH;
}
public Object readIndexEntry(Context context, ByteArrayBuffer reader) {
Slot s = new Slot(reader.readInt(), reader.readInt());
if (isInvalidSlot(s)){
return null;
}
return s;
}
public void writeIndexEntry(Context context, ByteArrayBuffer writer, Object entry) {
if(entry == null){
writer.writeInt(0);
writer.writeInt(0);
return;
}
if(entry instanceof StatefulBuffer){
StatefulBuffer entryAsWriter = (StatefulBuffer)entry;
writer.writeInt(entryAsWriter.getAddress());
writer.writeInt(entryAsWriter.length());
return;
}
if(entry instanceof Slot){
Slot s = (Slot) entry;
writer.writeInt(s.address());
writer.writeInt(s.length());
return;
}
throw new IllegalArgumentException();
}
public Object indexEntryToObject(Context context, Object indexEntry) {
if(indexEntry instanceof Slot){
Slot slot = (Slot)indexEntry;
indexEntry = bufferFromSlot(context, slot);
}
return unmarshall((ReadBuffer)indexEntry);
}
public Object readIndexEntry(ObjectIdContext context) throws CorruptionException, Db4oIOException {
int payLoadOffSet = context.readInt();
int length = context.readInt();
if(payLoadOffSet == 0){
return null;
}
return ((StatefulBuffer)context.buffer()).readPayloadWriter(payLoadOffSet, length);
}
public Object readIndexEntryFromObjectSlot(MarshallerFamily mf, StatefulBuffer buffer) throws CorruptionException, Db4oIOException {
int payLoadOffSet = buffer.readInt();
int length = buffer.readInt();
if(payLoadOffSet == 0){
return null;
}
return buffer.readPayloadWriter(payLoadOffSet, length);
}
protected abstract T fromByteArray(byte[] data);
protected abstract byte[] toByteArray(T obj);
protected abstract int compare(T x, T y);
private ByteArrayBuffer bufferFromSlot(Context context, Slot slot) {
return context.transaction().container().decryptedBufferByAddress(slot.address(), slot.length());
}
private T valueFrom(Object obj, Context context) {
if(obj instanceof Slot) {
obj = bufferFromSlot(context, (Slot)obj);
}
if(obj instanceof ReadBuffer) {
ReadBuffer buffer = (ReadBuffer)obj;
int offset = buffer.offset();
buffer.seek(0);
T number = unmarshall(buffer);
buffer.seek(offset);
return number;
}
return (T)obj;
}
private void skip(ReadBuffer context) {
int numBytes = context.readInt();
context.seek(context.offset() + numBytes);
}
private boolean isInvalidSlot(Slot slot) {
return slot.isNull();
}
private T unmarshall(final ReadBuffer buffer) {
byte[] data = new byte[buffer.readInt()];
buffer.readBytes(data);
return fromByteArray(data);
}
}