0001: /**
0002: * Copyright Mobixess Inc. 2007
0003: */package com.mobixess.jodb.core.io;
0004:
0005: import java.io.DataInput;
0006: import java.io.IOException;
0007: import java.io.PrintStream;
0008: import java.nio.ByteBuffer;
0009: import java.util.BitSet;
0010: import java.util.Vector;
0011:
0012: import com.mobixess.jodb.core.JodbIOException;
0013: import com.mobixess.jodb.core.index.IndexingRecord;
0014: import com.mobixess.jodb.core.transaction.JODBSession;
0015: import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
0016: import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
0017: import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
0018: import com.mobixess.jodb.util.Utils;
0019:
0020: /**
0021: * @author Mobixess
0022: *
0023: */
0024: public class ObjectDataContainer {
0025:
0026: public static enum FIELD_CATEGORIES {
0027: DIRECTLY_ADDRESSED, RELATIVELY_ADDRESSED, PRIMITIVE
0028: }
0029:
0030: //primary data mask shift
0031: private final static int DIRECT_ADDR_BIT_SHIFT = FIELD_CATEGORIES.DIRECTLY_ADDRESSED
0032: .ordinal();
0033: private final static int RELATIVE_ADDR_BIT_SHIFT = FIELD_CATEGORIES.RELATIVELY_ADDRESSED
0034: .ordinal();
0035: private final static int PRIMITIVE_BIT_SHIFT = FIELD_CATEGORIES.PRIMITIVE
0036: .ordinal();
0037: private final static int ARRAY_ID_BIT_SHIFT = FIELD_CATEGORIES
0038: .values().length;
0039: private final static int MODIFICATION_TS_BIT_SHIFT = FIELD_CATEGORIES
0040: .values().length + 1;
0041: private final static int CREATION_TS_BIT_SHIFT = FIELD_CATEGORIES
0042: .values().length + 2;
0043: private final static int UID_BIT_SHIFT = FIELD_CATEGORIES.values().length + 3;
0044: private final static int TRANSLATED_BIT_SHIFT = FIELD_CATEGORIES
0045: .values().length + 4;
0046:
0047: //secondary data mask
0048: private final static int AGENT_BIT_SHIFT = 7;
0049:
0050: private final static byte[] AUXILIARY_MAX_PRIMITIVE_CLEAN_ARRAY = new byte[64];
0051:
0052: private boolean _deleted;
0053: private short _id;
0054: private long _uid;
0055: private long _bodyLength;
0056: private long _headerLength;
0057: private long _createdTimeStamp;
0058: private long _modificationTimeStamp;
0059: private byte _primaryDataMask;
0060: private byte _secondaryDataMask;
0061: private long _redirectionOffset;
0062: private long _offset;
0063: private boolean _reseted;
0064: private long _auxiliaryDataStartOffset;
0065: private long _hierarchyDataStartOffset;
0066: private long _objectDataStartOffset;
0067: private IRandomAccessDataBuffer _input;
0068: private Vector<IndexingRecord> _indexes = new Vector<IndexingRecord>();
0069: private int _processedIndexes;
0070: private ObjectFieldsIterator _objectFieldsIterator = new ObjectFieldsIterator();
0071: private ArrayFieldsIterator _arrayFieldsIterator = new ArrayFieldsIterator();
0072: private FieldsIterator _activeIterator;
0073: private FieldRecord _recordCache = new FieldRecord();
0074:
0075: //private int[] _classHierarchy;
0076: private int _originalClassType;
0077:
0078: private ClassDescriptor _translatedClassDescriptor;
0079:
0080: private int _translatedClassType;
0081:
0082: private Class _arrayType;
0083:
0084: public ObjectDataContainer() {
0085: reset();
0086: }
0087:
0088: public void reset() {
0089: _deleted = false;
0090: _id = -1;
0091: _bodyLength = -1;
0092: _createdTimeStamp = -1;
0093: _uid = -1;
0094: _primaryDataMask = 0;
0095: _secondaryDataMask = 0;
0096: _redirectionOffset = -1;
0097: _offset = -1;
0098: _originalClassType = -1;
0099: _reseted = true;
0100: _auxiliaryDataStartOffset = -1;
0101: _hierarchyDataStartOffset = -1;
0102: _objectDataStartOffset = -1;
0103: _translatedClassType = -1;
0104: _input = null;
0105: _arrayType = null;
0106: _activeIterator = null;
0107: _indexes = null;
0108: _processedIndexes = 0;
0109: }
0110:
0111: private void setOffset(long offset) throws JodbIOException {
0112: if (!_reseted) {
0113: throw new JodbIOException(
0114: "Container must be reset before accepting new data");
0115: }
0116: _reseted = false;
0117: _offset = offset;
0118: }
0119:
0120: public long getOffset() {
0121: return _offset;
0122: }
0123:
0124: // public final ClassDescriptor getClassDescForOriginalType(JODBSession session) throws ClassNotStorableException, ClassNotFoundException{
0125: // int typeID = getOriginalClassType();
0126: // return session.getDescriptorForClass(typeID);
0127: // }
0128:
0129: public int getOriginalClassType() {
0130: return _originalClassType;
0131: }
0132:
0133: public boolean isDeleted() {
0134: return _deleted;
0135: }
0136:
0137: public boolean isTranslated() {
0138: return hasTranslatedBit(_primaryDataMask);
0139: }
0140:
0141: private void setDeleted(boolean deleted) {
0142: _deleted = deleted;
0143: }
0144:
0145: public Class getArrayType() {
0146: return _arrayType;
0147: }
0148:
0149: public short getId() {
0150: return _id;
0151: }
0152:
0153: private void setId(short id) {
0154: _id = id;
0155: }
0156:
0157: public boolean isRedirectedObject() {
0158: return JODBIOBase.hasRedirectedObjectModifier(_id);
0159: }
0160:
0161: public int getObjectTypeID() {
0162: return _id & JODBIOBase.LEN_MODIFIER_EXCLUSION_MASK
0163: & (~JODBIOBase.REDIRECTED_OBJECT_MODIFIER);
0164: }
0165:
0166: public int getLengthModifierFromID() {
0167: return _id & (~JODBIOBase.LEN_MODIFIER_EXCLUSION_MASK);
0168: }
0169:
0170: public long getBodyLength() {
0171: return _bodyLength;
0172: }
0173:
0174: public long getTotalLength() {
0175: return _headerLength + _bodyLength;
0176: }
0177:
0178: private void setLength(long headerLength, long bodyLength) {
0179: _headerLength = headerLength;
0180: _bodyLength = bodyLength;
0181: }
0182:
0183: public byte getPrimaryDataMask() {
0184: return _primaryDataMask;
0185: }
0186:
0187: public byte getSecondaryDataMask() {
0188: return _secondaryDataMask;
0189: }
0190:
0191: public long getUID() {
0192: return _uid;
0193: }
0194:
0195: public void setUID(long uid) {
0196: _uid = uid;
0197: }
0198:
0199: public long getCreatedTimeStamp() {
0200: return _createdTimeStamp;
0201: }
0202:
0203: private void setCreatedTimeStamp(long createdTimeStamp) {
0204: _createdTimeStamp = createdTimeStamp;
0205: }
0206:
0207: public long getModificationTimeStamp() {
0208: return _modificationTimeStamp;
0209: }
0210:
0211: private void setModificationTimeStamp(long modificationTimeStamp) {
0212: _modificationTimeStamp = modificationTimeStamp;
0213: }
0214:
0215: public static int addPrimitiveFieldsBit(int mask) {
0216: return (mask | (1 << PRIMITIVE_BIT_SHIFT));
0217: }
0218:
0219: public static boolean hasPrimitiveFieldsBit(int mask) {
0220: return (mask & (1 << PRIMITIVE_BIT_SHIFT)) != 0;
0221: }
0222:
0223: public static boolean hasTranslatedBit(int mask) {
0224: return (mask & (1 << TRANSLATED_BIT_SHIFT)) != 0;
0225: }
0226:
0227: public static boolean hasAgentBit(int mask) {
0228: return (mask & (1 << AGENT_BIT_SHIFT)) != 0;
0229: }
0230:
0231: public final boolean isJodbAgentObject() {
0232: return hasAgentBit(_secondaryDataMask);
0233: }
0234:
0235: public final boolean hasPrimitiveFields() {
0236: return hasPrimitiveFieldsBit(_primaryDataMask);
0237: }
0238:
0239: public static int addArrayIDBit(int mask) {
0240: return (mask | (1 << ARRAY_ID_BIT_SHIFT));
0241: }
0242:
0243: public static int addTranslatedBit(int mask) {
0244: return (mask | (1 << TRANSLATED_BIT_SHIFT));
0245: }
0246:
0247: public static int addAgentBit(int mask) {
0248: return (mask | (1 << AGENT_BIT_SHIFT));
0249: }
0250:
0251: public static boolean hasArrayIDBit(int mask) {
0252: return (mask & (1 << ARRAY_ID_BIT_SHIFT)) != 0;
0253: }
0254:
0255: public boolean isArray() {
0256: return hasArrayIDBit(_primaryDataMask);
0257: }
0258:
0259: // public boolean markAsArray(){
0260: // _dataMask = addArrayIDBit(_dataMask);
0261: // }
0262:
0263: public static int addDirectlyAddressedFieldsBit(int mask) {
0264: return (mask | (1 << DIRECT_ADDR_BIT_SHIFT));
0265: }
0266:
0267: public static boolean hasDirectlyAddressedFieldsBit(int mask) {
0268: return (mask & (1 << DIRECT_ADDR_BIT_SHIFT)) != 0;
0269: }
0270:
0271: public boolean hasDirectlyAddressedFields() {
0272: return hasDirectlyAddressedFieldsBit(_primaryDataMask);
0273: }
0274:
0275: public static int addRelativelyAddressedFieldsID(int mask) {
0276: return (mask | (1 << RELATIVE_ADDR_BIT_SHIFT));
0277: }
0278:
0279: public static boolean hasRelativelyAddressedFieldsBit(int mask) {
0280: return (mask & (1 << RELATIVE_ADDR_BIT_SHIFT)) != 0;
0281: }
0282:
0283: public static int addUIDFieldBit(int mask) {
0284: return (mask | (1 << UID_BIT_SHIFT));
0285: }
0286:
0287: public static boolean hasUIDFieldBit(int mask) {
0288: return (mask & (1 << UID_BIT_SHIFT)) != 0;
0289: }
0290:
0291: public boolean hasUIDField() {
0292: return hasUIDFieldBit(_primaryDataMask);
0293: }
0294:
0295: public static int addCreationTSFieldBit(int mask) {
0296: return (mask | (1 << CREATION_TS_BIT_SHIFT));
0297: }
0298:
0299: public static boolean hasCreationTSBit(int mask) {
0300: return (mask & (1 << CREATION_TS_BIT_SHIFT)) != 0;
0301: }
0302:
0303: public boolean hasCreationTSField() {
0304: return hasCreationTSBit(_primaryDataMask);
0305: }
0306:
0307: public static int addModificationTSFieldBit(int mask) {
0308: return (mask | (1 << MODIFICATION_TS_BIT_SHIFT));
0309: }
0310:
0311: public static boolean hasModificationTSBit(int mask) {
0312: return (mask & (1 << MODIFICATION_TS_BIT_SHIFT)) != 0;
0313: }
0314:
0315: public boolean hasModificationTSField() {
0316: return hasModificationTSBit(_primaryDataMask);
0317: }
0318:
0319: public boolean hasRelativelyAddressedFields() {
0320: return hasRelativelyAddressedFieldsBit(_primaryDataMask);
0321: }
0322:
0323: private void setRedirectionOffset(long redirectionOffset) {
0324: _redirectionOffset = redirectionOffset;
0325: }
0326:
0327: public long getRedirectionOffset() {
0328: return _redirectionOffset;
0329: }
0330:
0331: public boolean isRedirection() {
0332: return _redirectionOffset != -1;
0333: }
0334:
0335: // private void addField(int fieldID, Object value){
0336: // _records.add(new FieldRecord(fieldID,value));
0337: // }
0338: //
0339: // private void addField(int fieldID, long offset){
0340: // _records.add(new FieldRecord(fieldID,offset));
0341: // }
0342: //
0343: //
0344: //
0345: // public void getFieldsRecords(Vector<FieldRecord> result) {
0346: // result.addAll(_records);
0347: // }
0348:
0349: // public int[] getClassHierarchy() {
0350: // return _classHierarchy;
0351: // }
0352:
0353: public int getTranslatedClassType() {
0354: return _translatedClassType;
0355: }
0356:
0357: // private void setClassHierarchy(int[] classHierarchy) {
0358: // _classHierarchy = classHierarchy;
0359: // }
0360:
0361: /*package*/void printContent(IRandomAccessDataBuffer input,
0362: IOBase base, JODBSession session, long offset,
0363: boolean followRedirection, PrintStream printStream)
0364: throws IOException {
0365: reset();
0366: readHeader(input, offset, followRedirection);
0367: FieldsIterator fieldsIterator = null;
0368: if (!isDeleted() && !isRedirection()) {
0369: readAuxiliaryData();
0370: readHierarchyData(base, session);
0371: fieldsIterator = getFieldsIterator();
0372: }
0373: printStream.println("<<< Object Data Container: >>> "
0374: + "agent=" + isJodbAgentObject());
0375: printStream.println("Offset =" + _offset + " total len="
0376: + getTotalLength() + " Array=" + isArray()
0377: + " deleted=" + _deleted);
0378: printStream.println("Redirection=" + isRedirection() + ":"
0379: + _redirectionOffset + " Redirected="
0380: + isRedirectedObject());
0381: printStream.println("Class Hierarchy:");
0382: printStream.println("original type " + _originalClassType
0383: + " translated " + _translatedClassType);
0384: printStream.println("Fields:");
0385: //TODO restore
0386: for (int i = 0; fieldsIterator != null
0387: && fieldsIterator.hasNext(); i++) {
0388: _recordCache.clear();
0389: fieldsIterator.next(_recordCache, base);
0390: int fieldID = _recordCache._fieldID;
0391: String fieldName = base.getFullFieldNameForID(fieldID);
0392: printStream.println(" " + fieldID + " " + fieldName
0393: + " value=" + _recordCache._value + " offset="
0394: + _recordCache._objectOffset);
0395: }
0396: printStream.println("Object Data Container: >>>");
0397: }
0398:
0399: private boolean isClean() {
0400: return _reseted;
0401: }
0402:
0403: // public void init(IRandomAccessDataBuffer input, long offset, boolean followRedirection) throws IOException{
0404: // readHeader(input, offset, followRedirection);
0405: // }
0406:
0407: /**
0408: *
0409: * @param ioTicket
0410: * @return true if object deleted
0411: * @throws IOException
0412: */
0413: public void readHeader(IOTicket ticket, boolean followRedirection)
0414: throws IOException {
0415: IRandomAccessDataBuffer randomAccessDataBuffer = ticket
0416: .getRandomAccessBuffer();
0417: readHeader(randomAccessDataBuffer, randomAccessDataBuffer
0418: .getCursorOffset(), followRedirection);
0419: }
0420:
0421: /**
0422: *
0423: * @param ioTicket
0424: * @return true if object deleted
0425: * @throws IOException
0426: */
0427: public void readHeader(IOTicket ticket, boolean followRedirection,
0428: Vector<IndexingRecord> indexes) throws IOException {
0429: IRandomAccessDataBuffer randomAccessDataBuffer = ticket
0430: .getRandomAccessBuffer();
0431: readHeader(randomAccessDataBuffer, randomAccessDataBuffer
0432: .getCursorOffset(), followRedirection, indexes);
0433: }
0434:
0435: public void readHeader(IRandomAccessDataBuffer input, long offset,
0436: boolean followRedirection) throws IOException {
0437: readHeader(input, offset, followRedirection, null);
0438: }
0439:
0440: /**
0441: *
0442: * @param ioTicket
0443: * @return true if object deleted
0444: * @throws IOException
0445: */
0446: public void readHeader(IRandomAccessDataBuffer input, long offset,
0447: boolean followRedirection, Vector<IndexingRecord> indexes)
0448: throws IOException {
0449: if (!isClean()) {
0450: throw new IOException();
0451: }
0452: input.prefetch(offset);
0453: setOffset(offset);
0454: _input = input;
0455: _indexes = indexes;
0456: input.seek(offset);
0457: long recordStartOffset = input.getCursorOffset();
0458: short id = input.readShort();
0459: setId(id);
0460: long bodyLength = readEntryLen(id, input);
0461: long bodyStartOffset = input.getCursorOffset();
0462: setLength(bodyStartOffset - recordStartOffset, bodyLength);
0463: switch (getObjectTypeID()) {
0464: case JODBIOBase.ENTRY_EMPTY_ID:
0465: setDeleted(true);
0466: break;
0467: case JODBIOBase.ENTRY_OBJECT_ID:
0468: _primaryDataMask = input.readByte();
0469: _secondaryDataMask = input.readByte();
0470: //setDataMask(mask);
0471: break;
0472: case JODBIOBase.ENTRY_REDIRECTOR_ID:
0473: long redirectionOffset = input.readLong();
0474: if (followRedirection) {
0475: //input.seek(redirectionOffset);
0476: reset();
0477: readHeader(input, redirectionOffset, false);
0478: } else {
0479: setRedirectionOffset(redirectionOffset);
0480: }
0481: break;
0482: default:
0483: throw new JodbIOException("Illegal entry ID " + id);
0484: }
0485: _auxiliaryDataStartOffset = input.getCursorOffset();
0486: //setRemainingBytesInRecord( bodyLength - (_auxiliaryDataStartOffset - bodyStartOffset) );
0487: }
0488:
0489: public void readAuxiliaryData() throws IOException {
0490: if (_auxiliaryDataStartOffset == -1 || isDeleted()
0491: || isRedirection()) {
0492: throw new JodbIOException("Illegal IO state");
0493: }
0494: if (_hierarchyDataStartOffset != -1) {
0495: return;//data has been read already
0496: }
0497: _input.seek(_auxiliaryDataStartOffset);
0498: if (hasUIDField()) {
0499: long uid = _input.readLong();
0500: setUID(uid);
0501: }
0502: if (hasCreationTSField()) {
0503: long creationTS = _input.readLong();
0504: setCreatedTimeStamp(creationTS);
0505: }
0506: if (hasModificationTSField()) {
0507: long modifTS = _input.readLong();
0508: setModificationTimeStamp(modifTS);
0509: }
0510: _hierarchyDataStartOffset = _input.getCursorOffset();
0511: }
0512:
0513: public void readHierarchyData(IOBase base, JODBSession session)
0514: throws IOException {
0515: if (_hierarchyDataStartOffset == -1 || isDeleted()
0516: || isRedirection()) {
0517: throw new JodbIOException("Illegal IO state");
0518: }
0519: if (_objectDataStartOffset != -1) {
0520: return;//data has been read already
0521: }
0522: _input.seek(_hierarchyDataStartOffset);
0523:
0524: _originalClassType = _input.readShort() & 0xFFFF;
0525:
0526: if (isTranslated()) {
0527: _translatedClassType = _input.readShort() & 0xFFFF;
0528: } else {
0529: _translatedClassType = _originalClassType;
0530: }
0531:
0532: try {
0533: _translatedClassDescriptor = session
0534: .getDescriptorForClass(_translatedClassType);
0535: } catch (Exception e1) {
0536: //throw new IOException("reason: "+e1.getMessage()); //TODO add warning?
0537: }
0538:
0539: // int totalHierarchyIDs = _input.readShort()&0xFFFF;
0540: // int[] hierarchyIDs = new int[totalHierarchyIDs];
0541: // for (int i = 0; i < hierarchyIDs.length; i++) {
0542: // hierarchyIDs[i] = _input.readShort()&0xFFFF;
0543: // }
0544: // _classHierarchy = hierarchyIDs;
0545:
0546: _objectDataStartOffset = _input.getCursorOffset();
0547: if (isArray()) {
0548: String fieldType = base
0549: .getClassTypeForID(_translatedClassType);
0550: _arrayType = null;
0551: try {
0552: _arrayType = Class.forName(fieldType);
0553: } catch (ClassNotFoundException e) {
0554: _arrayType = PrimitiveJavaTypesUtil
0555: .primitiveClassForName(fieldType);
0556: if (_arrayType == null) {
0557: e.printStackTrace();
0558: }
0559: //TODO debug output???
0560: }
0561: }
0562: }
0563:
0564: public FieldsIterator readObject(JODBOperationContext context,
0565: long offset, boolean followRedirection) throws IOException {
0566: return readObject(
0567: context.getIoTicket().getRandomAccessBuffer(), context
0568: .getBase(), context.getSession(), offset,
0569: followRedirection, null);
0570: }
0571:
0572: public FieldsIterator readObject(JODBOperationContext context,
0573: long offset, boolean followRedirection,
0574: Vector<IndexingRecord> indexes) throws IOException {
0575: return readObject(
0576: context.getIoTicket().getRandomAccessBuffer(), context
0577: .getBase(), context.getSession(), offset,
0578: followRedirection, indexes);
0579: }
0580:
0581: public FieldsIterator readObject(
0582: IRandomAccessDataBuffer dataBuffer, IOBase base,
0583: JODBSession session, long offset, boolean followRedirection)
0584: throws IOException {
0585: return readObject(dataBuffer, base, session, offset,
0586: followRedirection, null);
0587: }
0588:
0589: public FieldsIterator readObject(
0590: IRandomAccessDataBuffer dataBuffer, IOBase base,
0591: JODBSession session, long offset,
0592: boolean followRedirection, Vector<IndexingRecord> indexes)
0593: throws IOException {
0594: readHeader(dataBuffer, offset, followRedirection, indexes);
0595: if (isDeleted() || isRedirection()) {
0596: resetInputSourceToEnd(base);
0597: return null;
0598: }
0599: readAuxiliaryData();
0600: readHierarchyData(base, session);
0601: if (isArray() && _arrayType == null) {
0602: return null;
0603: }
0604: return getFieldsIterator();
0605: }
0606:
0607: private FieldsIterator getFieldsIterator() throws IOException {
0608: if (_translatedClassDescriptor == null) {
0609: return null;
0610: }
0611: if (isArray()) {
0612: _arrayFieldsIterator.init();
0613: _activeIterator = _arrayFieldsIterator;
0614: return _arrayFieldsIterator;
0615: } else {
0616: _objectFieldsIterator.init();
0617: _activeIterator = _objectFieldsIterator;
0618: return _objectFieldsIterator;
0619: }
0620: }
0621:
0622: public FieldsIterator getActiveFieldsIterator() {
0623: return _activeIterator;
0624: }
0625:
0626: private static long readEntryLen(short entryID, DataInput input)
0627: throws IOException {
0628: switch (entryID
0629: & (JODBIOBase.LEN_MODIFIER_BYTE | JODBIOBase.LEN_MODIFIER_LONG)) {
0630: case JODBIOBase.LEN_MODIFIER_BYTE:
0631: return input.readByte() & 0xff;
0632: case JODBIOBase.LEN_MODIFIER_LONG:
0633: return input.readLong();
0634: case 0:
0635: return input.readShort() & 0xffff;
0636: default:
0637: throw new JodbIOException(
0638: "format error: unknown len modifier in id="
0639: + entryID);
0640: }
0641: }
0642:
0643: public void resetInputSourceToEnd(IOBase base) throws IOException {
0644: if (base != null && _activeIterator != null && _indexes != null) {
0645: while (_processedIndexes < _indexes.size()
0646: && _activeIterator.hasNext()) {
0647: _activeIterator.next(_recordCache, base, false);
0648: }
0649: }
0650: _input.seek(_offset + getTotalLength());
0651: }
0652:
0653: public long getEndOffset() {
0654: return _offset + getTotalLength();
0655: }
0656:
0657: public FieldRecord getRecordCache() {
0658: return _recordCache;
0659: }
0660:
0661: public ClassDescriptor getClassDescriptorForPersistedObject() {
0662: return _translatedClassDescriptor;
0663: }
0664:
0665: // public IndexingRecord getIndexingRecord(int fieldId){
0666: // if(_indexes == null){
0667: // return null;
0668: // }
0669: // for (int i = 0; i < _indexes.size() ; i++) {
0670: // IndexingRecord record = _indexes.elementAt(i);
0671: // if(record.getIndexingAgent().getClassId() == fieldId){
0672: // return record;
0673: // }
0674: // }
0675: // return null;
0676: // }
0677:
0678: public static class FieldRecord {
0679:
0680: public int _fieldID;
0681: public int _fieldTypeID;
0682: public String _fieldTypeName;
0683: public Object _value;
0684: public long _objectOffset;
0685: public ByteBuffer _primitiveRawDataBuffer = ByteBuffer
0686: .allocateDirect(16);//double the size of long, to make sure any primitive fits
0687: public FIELD_CATEGORIES _category;
0688:
0689: public FieldRecord() {
0690: }
0691:
0692: public FieldRecord(int fieldID, Object value) {
0693: super ();
0694: _fieldID = fieldID;
0695: _value = value;
0696: }
0697:
0698: public FieldRecord(int fieldID, long objectOffset) {
0699: super ();
0700: _fieldID = fieldID;
0701: _objectOffset = objectOffset;
0702: }
0703:
0704: public void clear() {
0705: _fieldID = -1;
0706: _value = null;
0707: _objectOffset = -1;
0708: _primitiveRawDataBuffer.clear();
0709: _category = null;
0710: _fieldTypeName = null;
0711: }
0712:
0713: @Override
0714: public String toString() {
0715: return "" + _fieldID + " " + _value + " " + _objectOffset;
0716: }
0717: }
0718:
0719: public interface FieldsIterator {
0720: boolean hasNext();
0721:
0722: void next(FieldRecord record, IOBase base) throws IOException;
0723:
0724: void next(FieldRecord record, IOBase base,
0725: boolean unfoldPrimitive) throws IOException;
0726:
0727: int getRemainingInCurrentCategory();
0728:
0729: void reset() throws IOException;
0730: }
0731:
0732: public class ArrayFieldsIterator implements FieldsIterator {
0733:
0734: private long[] _slot = new long[8];//allocate read cache, max 8 londs to cache
0735: private int _elementLen;
0736: private int _indexInSlot;
0737: private int _remainingElementsInArray;
0738: private byte _currentSlotMask;
0739: private long _slotStartOffset;
0740: private long _readingOffset;
0741:
0742: private void init() throws IOException {
0743: if (_objectDataStartOffset == -1 || _arrayType == null
0744: || isDeleted() || isRedirection()) {
0745: throw new JodbIOException("Illegal IO state");
0746: }
0747: _input.seek(_objectDataStartOffset);
0748: _remainingElementsInArray = _input.readInt();
0749: _elementLen = _input.readUnsignedByte();
0750: _indexInSlot = Integer.MAX_VALUE;
0751: _readingOffset = _input.getCursorOffset();
0752: if (!_arrayType.isPrimitive()) {
0753: checkNextSlot();
0754: }
0755: }
0756:
0757: private void checkNextSlot() throws IOException {
0758: if (_indexInSlot < 8 || _remainingElementsInArray == 0) {
0759: return;
0760: }
0761: _input.seek(_readingOffset);
0762: _indexInSlot = 0;
0763: int maxToRead = Math.min(8, _remainingElementsInArray);
0764: _slotStartOffset = _input.getCursorOffset();
0765: for (int i = 0; i < maxToRead; i++) {
0766: if (_elementLen > 0xFFFFFFFFL) {
0767: _slot[i] = _input.readLong();
0768: } else {
0769: _slot[i] = _input.readInt();
0770: }
0771: }
0772: _currentSlotMask = _input.readByte();
0773: _readingOffset = _input.getCursorOffset();
0774: }
0775:
0776: public final boolean hasNext() {
0777: return _remainingElementsInArray > 0;
0778: }
0779:
0780: private boolean isAbsoluteOffset() {
0781: return (_currentSlotMask & (1 << _indexInSlot)) != 0;
0782: }
0783:
0784: public void next(FieldRecord record, IOBase base,
0785: boolean unfoldPrimitive) throws IOException {
0786: if (!hasNext()) {
0787: throw new IOException();
0788: }
0789: if (_arrayType.isPrimitive()) {//read primitive
0790: if (unfoldPrimitive) {
0791: Object value = Utils.readPrimitive(_arrayType
0792: .getName(), _input);
0793: record._value = value;
0794: } else {
0795: record._primitiveRawDataBuffer.clear();
0796: record._primitiveRawDataBuffer.limit(_elementLen);
0797: _input.getChannel().read(
0798: record._primitiveRawDataBuffer);
0799: record._primitiveRawDataBuffer.flip();
0800: }
0801: _remainingElementsInArray--;
0802: return;
0803: }
0804: record._objectOffset = _slot[_indexInSlot];
0805: if (record._objectOffset != 0 && !isAbsoluteOffset()) {
0806: record._objectOffset += _slotStartOffset
0807: + (_indexInSlot + 1) * _elementLen;
0808: }
0809: _indexInSlot++;
0810: _remainingElementsInArray--;
0811: checkNextSlot();
0812: }
0813:
0814: public void next(FieldRecord record, IOBase base)
0815: throws IOException {
0816: next(record, base, true);
0817: }
0818:
0819: public int getRemainingInCurrentCategory() {
0820: return _remainingElementsInArray;
0821: }
0822:
0823: public void reset() throws IOException {
0824: init();
0825: }
0826:
0827: }
0828:
0829: public class ObjectFieldsIterator implements FieldsIterator {
0830: private FIELD_CATEGORIES _fieldsCategory;
0831: private int _remainingPersistentFieldsInCategory;
0832: private long _readingOffset;
0833: private BitSet _unprocessedFields = new BitSet();
0834:
0835: private void init() throws IOException {
0836: if (_objectDataStartOffset == -1 || isDeleted()
0837: || isRedirection()) {
0838: throw new JodbIOException("Illegal IO state");
0839: }
0840: _fieldsCategory = null;
0841: _remainingPersistentFieldsInCategory = 0;
0842: _unprocessedFields.clear();
0843: if (_translatedClassDescriptor != null) {
0844: int total = _translatedClassDescriptor.getFields().length;
0845: _unprocessedFields.set(0, total);
0846: }
0847: if (_objectDataStartOffset != _offset + getTotalLength()) {
0848: _input.seek(_objectDataStartOffset);
0849: checkNextCategoryNeed();
0850: }
0851: }
0852:
0853: private void checkNextCategoryNeed() throws IOException {
0854: while (_remainingPersistentFieldsInCategory == 0) {
0855: int index = _fieldsCategory == null ? 0
0856: : _fieldsCategory.ordinal() + 1;
0857: if (index < FIELD_CATEGORIES.values().length) {
0858: _fieldsCategory = FIELD_CATEGORIES.values()[index];
0859: if ((_primaryDataMask & (1 << index)) != 0) {
0860: _remainingPersistentFieldsInCategory = _input
0861: .readShort() & 0xFFFF;
0862: }
0863: } else {
0864: break;
0865: }
0866: }
0867: _readingOffset = _input.getCursorOffset();
0868: }
0869:
0870: public boolean hasNext() {
0871: return _unprocessedFields.cardinality() > 0;
0872: }
0873:
0874: private boolean hasNextPersistent() {
0875: return _remainingPersistentFieldsInCategory != 0;
0876: }
0877:
0878: public void next(FieldRecord record, IOBase base)
0879: throws IOException {
0880: next(record, base, true);
0881: }
0882:
0883: public void next(FieldRecord record, IOBase base,
0884: boolean unfoldPrimitive) throws IOException {
0885: if (!hasNext()) {
0886: throw new IOException();
0887: }
0888: if (hasNextPersistent())
0889: _input.seek(_readingOffset);
0890: boolean validRecord = false;
0891: while (hasNextPersistent()) {
0892: record._fieldID = _input.readShort() & 0xffff;
0893: String fieldID = base
0894: .getFullFieldNameForID(record._fieldID);
0895: record._fieldTypeID = fieldID.charAt(1);
0896: record._fieldTypeName = base
0897: .getClassTypeForID(record._fieldTypeID);
0898: record._category = _fieldsCategory;
0899: switch (_fieldsCategory) {
0900: case DIRECTLY_ADDRESSED:
0901: record._objectOffset = _input.readLong();
0902: break;
0903: case RELATIVELY_ADDRESSED:
0904: record._objectOffset = _input.readInt()
0905: + _input.getCursorOffset();
0906: break;
0907: case PRIMITIVE:
0908: record._primitiveRawDataBuffer.clear();
0909: IndexingRecord indexingRecord = IndexingRecord
0910: .findIndexingRecord(record._fieldID,
0911: _indexes);
0912: if (unfoldPrimitive) {
0913: Object value;
0914: if (indexingRecord != null) {
0915: int dataLen = PrimitiveJavaTypesUtil
0916: .getDataOutputWriteLen(record._fieldTypeName);
0917: record._primitiveRawDataBuffer
0918: .limit(dataLen);
0919: ByteBuffer buffer = indexingRecord
0920: .getPersistedDataBuffer();
0921: _input.getChannel().read(buffer);
0922: buffer.flip();
0923: value = PrimitiveJavaTypesUtil
0924: .getAsWrappedPrimitive(
0925: PrimitiveJavaTypesUtil
0926: .getEnumeratedType(record._fieldTypeName),
0927: buffer);
0928: _processedIndexes++;
0929: } else {
0930: value = Utils.readPrimitive(
0931: record._fieldTypeName, _input);
0932: }
0933: record._value = value;
0934: } else {
0935: int dataLen = PrimitiveJavaTypesUtil
0936: .getDataOutputWriteLen(record._fieldTypeName);
0937: record._primitiveRawDataBuffer.limit(dataLen);
0938: _input.getChannel().read(
0939: record._primitiveRawDataBuffer);
0940: record._primitiveRawDataBuffer.flip();
0941: if (indexingRecord != null) {
0942: indexingRecord
0943: .setPersistedDataBufferValue(record._primitiveRawDataBuffer);
0944: record._primitiveRawDataBuffer.rewind();
0945: _processedIndexes++;
0946: }
0947: }
0948: }
0949: _remainingPersistentFieldsInCategory--;
0950: checkNextCategoryNeed();
0951: if (_translatedClassDescriptor != null) {
0952: int fieldIndex = _translatedClassDescriptor
0953: .getFieldIndexForID(record._fieldID);
0954: if (fieldIndex == -1) {//field doesn't exist in class definition
0955: record.clear();
0956: continue;
0957: } else {
0958: _unprocessedFields.clear(fieldIndex);
0959: }
0960: }
0961: validRecord = true;
0962: break;
0963: }
0964: if (!validRecord && _translatedClassDescriptor != null) {
0965: int nextUnrocessedIndex = _unprocessedFields
0966: .nextSetBit(0);
0967: if (nextUnrocessedIndex == -1) {
0968: throw new JodbIOException(
0969: "nextUnrocessedIndex == -1)");
0970: }
0971: FieldAndIDRecord fieldAndIDRecord = _translatedClassDescriptor
0972: .getFields()[nextUnrocessedIndex];
0973: Class fieldType = fieldAndIDRecord._field.getType();
0974: record._fieldID = fieldAndIDRecord._id;
0975: IndexingRecord indexingRecord = IndexingRecord
0976: .findIndexingRecord(record._fieldID, _indexes);
0977: record._fieldTypeName = fieldType.getName();
0978: record._fieldTypeID = base
0979: .getOrSetClassTypeSubstitutionID(record._fieldTypeName);
0980: if (fieldType.isPrimitive()) {
0981: record._category = FIELD_CATEGORIES.PRIMITIVE;
0982: if (unfoldPrimitive) {
0983: record._value = PrimitiveJavaTypesUtil
0984: .getDefaultWrapperInstance(record._fieldTypeName);
0985: } else {
0986: int dataLen = PrimitiveJavaTypesUtil
0987: .getDataOutputWriteLen(record._fieldTypeName);
0988: record._primitiveRawDataBuffer.limit(dataLen);
0989: record._primitiveRawDataBuffer.put(
0990: AUXILIARY_MAX_PRIMITIVE_CLEAN_ARRAY, 0,
0991: dataLen);
0992: record._primitiveRawDataBuffer.flip();
0993: }
0994: if (indexingRecord != null) {
0995: indexingRecord
0996: .setPersistedDataBufferValue(PrimitiveJavaTypesUtil
0997: .getDefaultValueAsByteBuffer(record._fieldTypeName));
0998: _processedIndexes++;
0999: }
1000: } else {
1001: record._category = FIELD_CATEGORIES.RELATIVELY_ADDRESSED;
1002: record._objectOffset = 0;
1003: }
1004: _unprocessedFields.clear(nextUnrocessedIndex);
1005: }
1006:
1007: }
1008:
1009: public int getRemainingInCurrentCategory() {
1010: return _remainingPersistentFieldsInCategory;
1011: }
1012:
1013: public void reset() throws IOException {
1014: init();
1015: }
1016: }
1017: }
|