/* 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.marshall;
import com.db4o.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
import com.db4o.internal.activation.*;
import com.db4o.internal.slots.*;
import com.db4o.marshall.*;
import com.db4o.typehandlers.*;
/**
* @exclude
*/
public class MarshallingContext implements MarshallingInfo, WriteContext {
private static final int HEADER_LENGTH = Const4.LEADING_LENGTH
+ Const4.ID_LENGTH // YapClass ID
+ 1 // Marshaller Version
+ Const4.INT_LENGTH; // number of fields
private final Transaction _transaction;
private final ObjectReference _reference;
private UpdateDepth _updateDepth;
private final boolean _isNew;
private final BitMap4 _nullBitMap;
private final MarshallingBuffer _writeBuffer;
private MarshallingBuffer _currentBuffer;
private ByteArrayBuffer _debugPrepend;
private Object _currentMarshalledObject;
private Object _currentIndexEntry;
private int _declaredAspectCount;
public MarshallingContext(Transaction trans, ObjectReference ref, UpdateDepth updateDepth, boolean isNew) {
_transaction = trans;
_reference = ref;
_nullBitMap = new BitMap4(aspectCount());
_updateDepth = classMetadata().adjustUpdateDepth(trans, updateDepth);
_isNew = isNew;
_writeBuffer = new MarshallingBuffer();
_currentBuffer = _writeBuffer;
}
private int aspectCount() {
return classMetadata().aspectCount();
}
public ClassMetadata classMetadata() {
return _reference.classMetadata();
}
public boolean isNew() {
return _isNew;
}
public boolean isNull(int fieldIndex) {
// TODO Auto-generated method stub
return false;
}
public void isNull(int fieldIndex, boolean flag) {
_nullBitMap.set(fieldIndex, flag);
}
public Transaction transaction() {
return _transaction;
}
public Slot allocateNewSlot(int length){
if(_transaction instanceof LocalTransaction){
return localContainer().allocateSlotForNewUserObject(_transaction, objectID(), length);
}
return new Slot(Slot.NEW, length);
}
private Slot allocateUpdateSlot(int length){
if(_transaction instanceof LocalTransaction){
return localContainer().allocateSlotForUserObjectUpdate(transaction(), objectID(), length);
}
return new Slot(Slot.UPDATE, length);
}
private LocalObjectContainer localContainer() {
return ((LocalTransaction)transaction()).localContainer();
}
public Pointer4 allocateSlot(){
int length = container().blockConverter().blockAlignedBytes(marshalledLength());
Slot slot = isNew() ? allocateNewSlot(length) : allocateUpdateSlot(length);
return new Pointer4(objectID(), slot);
}
public ByteArrayBuffer toWriteBuffer(Pointer4 pointer) {
ByteArrayBuffer buffer = new ByteArrayBuffer(pointer.length());
_writeBuffer.mergeChildren(this, pointer.address(), writeBufferOffset());
if (Deploy.debug) {
buffer.writeBegin(Const4.YAPOBJECT);
}
writeObjectClassID(buffer, classMetadata().getID());
buffer.writeByte(HandlerRegistry.HANDLER_VERSION);
buffer.writeInt(aspectCount());
buffer.writeBitMap(_nullBitMap);
_writeBuffer.transferContentTo(buffer);
if (Deploy.debug) {
buffer.writeEnd();
}
return buffer;
}
private int writeBufferOffset(){
return HEADER_LENGTH + _nullBitMap.marshalledLength();
}
public int marshalledLength() {
int length = writeBufferOffset();
_writeBuffer.checkBlockAlignment(this, null, new IntByRef(length));
return length + _writeBuffer.marshalledLength() + Const4.BRACKETS_BYTES;
}
public int requiredLength(MarshallingBuffer buffer, boolean align) {
if(! align){
return buffer.length();
}
return container().blockConverter().blockAlignedBytes(buffer.length());
}
private void writeObjectClassID(ByteArrayBuffer reader, int id) {
reader.writeInt(-id);
}
public Object getObject() {
return _reference.getObject();
}
public Config4Class classConfiguration() {
return classMetadata().config();
}
public UpdateDepth updateDepth() {
return _updateDepth;
}
public void updateDepth(UpdateDepth depth) {
_updateDepth = depth;
}
public int objectID() {
return _reference.getID();
}
public Object currentIndexEntry() {
// TODO Auto-generated method stub
return null;
}
public ObjectContainerBase container() {
return transaction().container();
}
public ObjectContainer objectContainer() {
return transaction().objectContainer();
}
public void writeByte(byte b) {
preWrite();
_currentBuffer.writeByte(b);
postWrite();
}
public void writeBytes(byte[] bytes) {
preWrite();
_currentBuffer.writeBytes(bytes);
postWrite();
}
public void writeInt(int i) {
preWrite();
_currentBuffer.writeInt(i);
postWrite();
}
public void writeLong(long l) {
preWrite();
_currentBuffer.writeLong(l);
postWrite();
}
private void preWrite() {
if(Deploy.debug){
if(_debugPrepend != null){
for (int i = 0; i < _debugPrepend.offset(); i++) {
_currentBuffer.writeByte(_debugPrepend._buffer[i]);
}
}
}
}
private void postWrite(){
if(Deploy.debug){
if(_debugPrepend != null){
_currentBuffer.debugDecrementLastOffset(_debugPrepend.offset());
_debugPrepend = null;
}
}
}
public void createChildBuffer(boolean storeLengthInLink) {
MarshallingBuffer childBuffer = _currentBuffer.addChild(false, storeLengthInLink);
_currentBuffer.reserveChildLinkSpace(storeLengthInLink);
_currentBuffer = childBuffer;
}
public void beginSlot(){
_currentBuffer = _writeBuffer;
}
public void writeDeclaredAspectCount(int count) {
_writeBuffer.writeInt(count);
}
public void debugPrependNextWrite(ByteArrayBuffer prepend) {
if(Deploy.debug){
_debugPrepend = prepend;
}
}
public void debugWriteEnd(byte b) {
_currentBuffer.writeByte(b);
}
public void writeObject(Object obj) {
int id = container().storeInternal(transaction(), obj, _updateDepth, true);
writeInt(id);
_currentMarshalledObject = obj;
_currentIndexEntry = new Integer(id);
}
public void writeObject(TypeHandler4 handler, Object obj){
MarshallingContextState state = currentState();
writeObjectWithCurrentState(handler, obj);
restoreState(state);
}
public void writeObjectWithCurrentState(TypeHandler4 handler, Object obj) {
if(Handlers4.useDedicatedSlot(this, handler)){
writeObject(obj);
}else{
if(obj == null){
writeNullReference(handler);
} else{
createIndirectionWithinSlot(handler);
handler.write(this, obj);
}
}
}
private void writeNullReference(TypeHandler4 handler){
if( isIndirectedWithinSlot(handler)){
writeNullLink();
return;
}
Handlers4.write(handler, this, Handlers4.nullRepresentationInUntypedArrays(handler));
}
private void writeNullLink(){
writeInt(0);
writeInt(0);
}
public void addIndexEntry(FieldMetadata fieldMetadata, Object obj) {
if(! _currentBuffer.hasParent()){
Object indexEntry = (obj == _currentMarshalledObject) ? _currentIndexEntry : obj;
if(_isNew || !updateDepth().canSkip(_reference)) {
fieldMetadata.addIndexEntry(transaction(), objectID(), indexEntry);
}
return;
}
_currentBuffer.requestIndexEntry(fieldMetadata);
}
public void purgeFieldIndexEntriesOnUpdate(Transaction transaction, ArrayType arrayType) {
if(!updateDepth().canSkip(_reference)) {
transaction.writeUpdateAdjustIndexes(_reference.getID(), _reference.classMetadata(), arrayType);
}
}
public ObjectReference reference(){
return _reference;
}
public void createIndirectionWithinSlot(TypeHandler4 handler) {
if(isIndirectedWithinSlot(handler)){
createIndirectionWithinSlot();
}
}
public void createIndirectionWithinSlot() {
createChildBuffer(true);
}
private boolean isIndirectedWithinSlot(TypeHandler4 handler) {
return SlotFormat.current().isIndirectedWithinSlot(handler);
}
// FIXME: This method was just temporarily added to fulfill contract of MarshallingInfo
// It will go, the buffer is never needed in new marshalling.
public ReadBuffer buffer() {
return null;
}
public MarshallingContextState currentState(){
return new MarshallingContextState(_currentBuffer);
}
public void restoreState(MarshallingContextState state){
_currentBuffer = state._buffer;
}
public ReservedBuffer reserve(final int length) {
preWrite();
ReservedBuffer reservedBuffer = _currentBuffer.reserve(length);
postWrite();
return reservedBuffer;
}
public int declaredAspectCount() {
return _declaredAspectCount;
}
public void declaredAspectCount(int count) {
_declaredAspectCount = count;
}
}