001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal.marshall;
022:
023: import com.db4o.*;
024: import com.db4o.foundation.*;
025: import com.db4o.internal.*;
026: import com.db4o.internal.handlers.*;
027: import com.db4o.internal.slots.*;
028: import com.db4o.marshall.*;
029:
030: /**
031: * @exclude
032: */
033: public class MarshallingContext implements FieldListInfo,
034: MarshallingInfo, WriteContext {
035:
036: private static final int HEADER_LENGTH = Const4.LEADING_LENGTH
037: + Const4.ID_LENGTH // YapClass ID
038: + 1 // Marshaller Version
039: + Const4.INT_LENGTH; // number of fields
040:
041: public static final byte HANDLER_VERSION = (byte) 2;
042:
043: private static final int NO_INDIRECTION = 3; // and number above 2
044:
045: private final Transaction _transaction;
046:
047: private final ObjectReference _reference;
048:
049: private int _updateDepth;
050:
051: private final boolean _isNew;
052:
053: private final BitMap4 _nullBitMap;
054:
055: private final MarshallingBuffer _writeBuffer;
056:
057: private MarshallingBuffer _currentBuffer;
058:
059: private int _fieldWriteCount;
060:
061: private Buffer _debugPrepend;
062:
063: private Object _currentMarshalledObject;
064:
065: private Object _currentIndexEntry;
066:
067: public MarshallingContext(Transaction trans, ObjectReference ref,
068: int updateDepth, boolean isNew) {
069: _transaction = trans;
070: _reference = ref;
071: _nullBitMap = new BitMap4(fieldCount());
072: _updateDepth = classMetadata().adjustUpdateDepth(trans,
073: updateDepth);
074: _isNew = isNew;
075: _writeBuffer = new MarshallingBuffer();
076: _currentBuffer = _writeBuffer;
077: }
078:
079: private int fieldCount() {
080: return classMetadata().fieldCount();
081: }
082:
083: public ClassMetadata classMetadata() {
084: return _reference.classMetadata();
085: }
086:
087: public boolean isNew() {
088: return _isNew;
089: }
090:
091: public boolean isNull(int fieldIndex) {
092: // TODO Auto-generated method stub
093:
094: return false;
095: }
096:
097: public void isNull(int fieldIndex, boolean flag) {
098: _nullBitMap.set(fieldIndex, flag);
099: }
100:
101: public Transaction transaction() {
102: return _transaction;
103: }
104:
105: private Slot createNewSlot(int length) {
106: Slot slot = new Slot(-1, length);
107: if (_transaction instanceof LocalTransaction) {
108: slot = ((LocalTransaction) _transaction).file().getSlot(
109: length);
110: _transaction.slotFreeOnRollback(objectID(), slot);
111: }
112: _transaction.setPointer(objectID(), slot);
113: return slot;
114: }
115:
116: private Slot createUpdateSlot(int length) {
117: if (transaction() instanceof LocalTransaction) {
118: return ((LocalTransaction) transaction())
119: .file()
120: .getSlotForUpdate(transaction(), objectID(), length);
121: }
122: return new Slot(0, length);
123: }
124:
125: public Pointer4 allocateSlot() {
126: int length = container().blockAlignedBytes(marshalledLength());
127: Slot slot = isNew() ? createNewSlot(length)
128: : createUpdateSlot(length);
129: return new Pointer4(objectID(), slot);
130: }
131:
132: public Buffer ToWriteBuffer(Pointer4 pointer) {
133:
134: Buffer buffer = new Buffer(pointer.length());
135: _writeBuffer.mergeChildren(this , pointer.address(),
136: writeBufferOffset());
137:
138: if (Deploy.debug) {
139: buffer.writeBegin(Const4.YAPOBJECT);
140: }
141:
142: writeObjectClassID(buffer, classMetadata().getID());
143: buffer.writeByte(HANDLER_VERSION);
144: buffer.writeInt(fieldCount());
145: buffer.writeBitMap(_nullBitMap);
146:
147: _writeBuffer.transferContentTo(buffer);
148:
149: if (Deploy.debug) {
150: buffer.writeEnd();
151: }
152:
153: return buffer;
154: }
155:
156: private int writeBufferOffset() {
157: return HEADER_LENGTH + _nullBitMap.marshalledLength();
158: }
159:
160: private int marshalledLength() {
161: int length = writeBufferOffset();
162: _writeBuffer.checkBlockAlignment(this , null, new IntByRef(
163: length));
164: return length + _writeBuffer.marshalledLength()
165: + Const4.BRACKETS_BYTES;
166: }
167:
168: public int requiredLength(MarshallingBuffer buffer, boolean align) {
169: if (!align) {
170: return buffer.length();
171: }
172: return container().blockAlignedBytes(buffer.length());
173: }
174:
175: private void writeObjectClassID(Buffer reader, int id) {
176: reader.writeInt(-id);
177: }
178:
179: public Object getObject() {
180: return _reference.getObject();
181: }
182:
183: public Config4Class classConfiguration() {
184: return classMetadata().config();
185: }
186:
187: public int updateDepth() {
188: return _updateDepth;
189: }
190:
191: public void updateDepth(int depth) {
192: _updateDepth = depth;
193: }
194:
195: public int objectID() {
196: return _reference.getID();
197: }
198:
199: public Object currentIndexEntry() {
200: // TODO Auto-generated method stub
201: return null;
202: }
203:
204: public ObjectContainerBase container() {
205: return transaction().container();
206: }
207:
208: public ObjectContainer objectContainer() {
209: return transaction().objectContainer();
210: }
211:
212: public void writeByte(byte b) {
213: preWrite();
214: _currentBuffer.writeByte(b);
215: postWrite();
216: }
217:
218: public void writeBytes(byte[] bytes) {
219: preWrite();
220: _currentBuffer.writeBytes(bytes);
221: postWrite();
222: }
223:
224: public void writeInt(int i) {
225: preWrite();
226: _currentBuffer.writeInt(i);
227: postWrite();
228: }
229:
230: public void writeLong(long l) {
231: preWrite();
232: _currentBuffer.writeLong(l);
233: postWrite();
234: }
235:
236: private void preWrite() {
237: _fieldWriteCount++;
238: if (isSecondWriteToField()) {
239: createChildBuffer(true, true);
240: }
241: if (Deploy.debug) {
242: if (_debugPrepend != null) {
243: for (int i = 0; i < _debugPrepend.offset(); i++) {
244: _currentBuffer.writeByte(_debugPrepend._buffer[i]);
245: }
246: }
247: }
248: }
249:
250: private void postWrite() {
251: if (Deploy.debug) {
252: if (_debugPrepend != null) {
253: _currentBuffer.debugDecrementLastOffset(_debugPrepend
254: .offset());
255: _debugPrepend = null;
256: }
257: }
258: }
259:
260: public void createChildBuffer(boolean transferLastWrite,
261: boolean storeLengthInLink) {
262: MarshallingBuffer childBuffer = _currentBuffer.addChild(false,
263: storeLengthInLink);
264: if (transferLastWrite) {
265: _currentBuffer.transferLastWriteTo(childBuffer,
266: storeLengthInLink);
267: }
268: _currentBuffer.reserveChildLinkSpace(storeLengthInLink);
269: _currentBuffer = childBuffer;
270: }
271:
272: private boolean isSecondWriteToField() {
273: return _fieldWriteCount == 2;
274: }
275:
276: public void nextField() {
277: _fieldWriteCount = 0;
278: _currentBuffer = _writeBuffer;
279: }
280:
281: public void fieldCount(int fieldCount) {
282: _writeBuffer.writeInt(fieldCount);
283: }
284:
285: public void debugPrependNextWrite(Buffer prepend) {
286: if (Deploy.debug) {
287: _debugPrepend = prepend;
288: }
289: }
290:
291: public void debugWriteEnd(byte b) {
292: _currentBuffer.writeByte(b);
293: }
294:
295: public void writeObject(Object obj) {
296:
297: int id = container().setInternal(transaction(), obj,
298: _updateDepth, true);
299:
300: writeInt(id);
301:
302: _currentMarshalledObject = obj;
303: _currentIndexEntry = new Integer(id);
304: }
305:
306: public void writeObject(TypeHandler4 handler, Object obj) {
307:
308: MarshallingContextState state = currentState();
309:
310: if (obj == null) {
311:
312: // TODO: This should never happen. All handlers should take care
313: // of nulls on a higher level, otherwise primitive wrappers
314: // default to their primitive values.
315:
316: // Consider to throw an IllegalArgumentException here to
317: // prevent users from calling with null arguments.
318:
319: writeNullObject(handler);
320:
321: } else {
322: createIndirection(handler);
323: handler.write(this , obj);
324: }
325:
326: restoreState(state);
327: }
328:
329: private void writeNullObject(TypeHandler4 handler) {
330: if (handlerRegistry().isVariableLength(handler)) {
331: doNotIndirectWrites();
332: writeNullLink();
333: return;
334: }
335:
336: if (handler instanceof PrimitiveHandler) {
337: PrimitiveHandler primitiveHandler = (PrimitiveHandler) handler;
338: handler.write(this , primitiveHandler
339: .nullRepresentationInUntypedArrays());
340: return;
341: }
342:
343: handler.write(this , null);
344: }
345:
346: private void writeNullLink() {
347: writeInt(0);
348: writeInt(0);
349: }
350:
351: public void addIndexEntry(FieldMetadata fieldMetadata, Object obj) {
352: if (!_currentBuffer.hasParent()) {
353: Object indexEntry = (obj == _currentMarshalledObject) ? _currentIndexEntry
354: : obj;
355: fieldMetadata.addIndexEntry(transaction(), objectID(),
356: indexEntry);
357: return;
358: }
359: _currentBuffer.requestIndexEntry(fieldMetadata);
360: }
361:
362: public ObjectReference reference() {
363: return _reference;
364: }
365:
366: public void doNotIndirectWrites() {
367: _fieldWriteCount = NO_INDIRECTION;
368: }
369:
370: public void prepareIndirectionOfSecondWrite() {
371: _fieldWriteCount = 0;
372: }
373:
374: private HandlerRegistry handlerRegistry() {
375: return container().handlers();
376: }
377:
378: public void createIndirection(TypeHandler4 handler) {
379: if (handlerRegistry().isVariableLength(handler)) {
380: createChildBuffer(false, true);
381: doNotIndirectWrites();
382: }
383: }
384:
385: // FIXME: This method was just temporarily added to fulfill contract of MarshallingInfo
386: // It will go, the buffer is never needed in new marshalling.
387: public Buffer buffer() {
388: return null;
389: }
390:
391: public MarshallingContextState currentState() {
392: return new MarshallingContextState(_currentBuffer,
393: _fieldWriteCount);
394: }
395:
396: public void restoreState(MarshallingContextState state) {
397: _currentBuffer = state._buffer;
398: _fieldWriteCount = state._fieldWriteCount;
399: }
400:
401: }
|