Package com.mobixess.jodb.core.io

Source Code of com.mobixess.jodb.core.io.ObjectDataContainer

/**
* Copyright Mobixess Inc. 2007
*/
package com.mobixess.jodb.core.io;

import java.io.DataInput;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.util.BitSet;
import java.util.Vector;

import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.index.IndexingRecord;
import com.mobixess.jodb.core.transaction.JODBSession;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
import com.mobixess.jodb.util.Utils;


/**
* @author Mobixess
*
*/
public class ObjectDataContainer {
   
    public static enum FIELD_CATEGORIES{DIRECTLY_ADDRESSED, RELATIVELY_ADDRESSED, PRIMITIVE}
   
    //primary data mask shift
    private final static int DIRECT_ADDR_BIT_SHIFT = FIELD_CATEGORIES.DIRECTLY_ADDRESSED.ordinal();
    private final static int RELATIVE_ADDR_BIT_SHIFT = FIELD_CATEGORIES.RELATIVELY_ADDRESSED.ordinal();
    private final static int PRIMITIVE_BIT_SHIFT = FIELD_CATEGORIES.PRIMITIVE.ordinal();
    private final static int ARRAY_ID_BIT_SHIFT = FIELD_CATEGORIES.values().length ;
    private final static int MODIFICATION_TS_BIT_SHIFT = FIELD_CATEGORIES.values().length + 1 ;
    private final static int CREATION_TS_BIT_SHIFT = FIELD_CATEGORIES.values().length+2;
    private final static int UID_BIT_SHIFT = FIELD_CATEGORIES.values().length+3;
    private final static int TRANSLATED_BIT_SHIFT = FIELD_CATEGORIES.values().length+4;
   
   
    //secondary data mask
    private final static int AGENT_BIT_SHIFT = 7;
    private final static int CYCLICAL_COUNTER_BIT_SHIFT = AGENT_BIT_SHIFT-1;
   
   
    private final static byte[] AUXILIARY_MAX_PRIMITIVE_CLEAN_ARRAY = new byte[64];
   


    private boolean _deleted;
    private short _id;
    private long _uid;
    private long _bodyLength;
    private long _headerLength;
    private long _createdTimeStamp;
    private long _modificationTimeStamp;
    private byte _primaryDataMask;
    private byte _secondaryDataMask;
    private long _redirectionOffset;
    private long _offset;
    private boolean _reseted;
    private long _auxiliaryDataStartOffset;
    private long _hierarchyDataStartOffset;
    private long _objectDataStartOffset;
    private short _cyclicVersionCounter;
    private IRandomAccessDataBuffer _input;
    private Vector<IndexingRecord> _indexes = new Vector<IndexingRecord>();
    private int _processedIndexes;
    private int _hashIdentity;
    private ObjectFieldsIterator _objectFieldsIterator = new ObjectFieldsIterator();
    private ArrayFieldsIterator _arrayFieldsIterator = new ArrayFieldsIterator();
    private FieldsIterator _activeIterator;
    private FieldRecord _recordCache = new FieldRecord();
   
    //private int[] _classHierarchy;
    private int _originalClassType;
   
    private ClassDescriptor _translatedClassDescriptor;
   
    private int _translatedClassType;
   
    private Class _arrayType;

   
    public ObjectDataContainer() {
        reset();
    }
   
    public void reset(){
        _deleted = false;
        _id = -1;
        _bodyLength = -1;
        _createdTimeStamp = -1;
        _uid = -1;
        _primaryDataMask = 0;
        _secondaryDataMask = 0;
        _redirectionOffset = -1;
        _offset = -1;
        _originalClassType = -1;
        _reseted = true;
        _auxiliaryDataStartOffset = -1;
        _hierarchyDataStartOffset = -1;
        _objectDataStartOffset = -1;
        _translatedClassType = -1;
        _hashIdentity = -1;
        _input = null;
        _arrayType = null;
        _activeIterator = null;
        _indexes = null;
        _processedIndexes = 0;
        _cyclicVersionCounter = 0;
    }
   
    private void setOffset(long offset) throws JodbIOException {
        if(!_reseted){
            throw new JodbIOException("Container must be reset before accepting new data");
        }
        _reseted = false;
        _offset = offset;
    }
   
    public long getOffset() {
        return _offset;
    }
   
    public short getCyclicVersionCounter() {
        return _cyclicVersionCounter;
    }
   
//    public final ClassDescriptor getClassDescForOriginalType(JODBSession session) throws ClassNotStorableException, ClassNotFoundException{
//        int typeID = getOriginalClassType();
//        return session.getDescriptorForClass(typeID);
//    }
   
    public int getOriginalClassType() {
        return _originalClassType;
    }
   
    public boolean isDeleted() {
        return _deleted;
    }
   
    public boolean isTranslated() {
        return hasTranslatedBit(_primaryDataMask);
    }
   
    private void setDeleted(boolean deleted) {
        _deleted = deleted;
    }
   
    public Class getArrayType() {
        return _arrayType;
    }

    public short getId() {
        return _id;
    }

    private void setId(short id) {
        _id = id;
    }
   
    public int getHashIdentity() throws IOException{
        if(_hashIdentity == -1){
            calcHashIdentity();
        }
        return _hashIdentity;
    }
   
    private void calcHashIdentity() throws IOException{
        long positionBefore = _input.getCursorOffset();
        _input.seek(_offset);
        _hashIdentity = Utils.oathash(_input, getTotalLength());
        if(positionBefore != _input.getCursorOffset()){
            _input.seek(positionBefore);
        }
    }
   
    public boolean isRedirectedObject(){
        return JODBIOBase.hasRedirectedObjectModifier(_id);
    }
   
    public int getObjectTypeID(){
        return _id & JODBIOBase.LEN_MODIFIER_EXCLUSION_MASK & (~JODBIOBase.REDIRECTED_OBJECT_MODIFIER);
    }
   
    public int getLengthModifierFromID(){
        return _id & (~JODBIOBase.LEN_MODIFIER_EXCLUSION_MASK) ;
    }

    public long getBodyLength() {
        return _bodyLength;
    }
   
    public long getTotalLength(){
        return _headerLength+_bodyLength;
    }

    private void setLength(long headerLength, long bodyLength) {
        _headerLength = headerLength;
        _bodyLength = bodyLength;
    }

    public byte getPrimaryDataMask() {
        return _primaryDataMask;
    }
   
    public byte getSecondaryDataMask() {
        return _secondaryDataMask;
    }

    public long getUID() {
        return _uid;
    }

    public void setUID(long uid) {
        _uid = uid;
    }
   
    public long getCreatedTimeStamp() {
        return _createdTimeStamp;
    }
   
    private void setCreatedTimeStamp(long createdTimeStamp) {
        _createdTimeStamp = createdTimeStamp;
    }

    public long getModificationTimeStamp() {
        return _modificationTimeStamp;
    }

    private void setModificationTimeStamp(long modificationTimeStamp) {
        _modificationTimeStamp = modificationTimeStamp;
    }

    public static int addPrimitiveFieldsBit(int mask){
        return (mask|(1<<PRIMITIVE_BIT_SHIFT));
    }

    public static boolean hasPrimitiveFieldsBit(int mask){
        return (mask&(1<<PRIMITIVE_BIT_SHIFT))!=0;
    }
   
    public static boolean hasTranslatedBit(int mask){
        return (mask&(1<<TRANSLATED_BIT_SHIFT))!=0;
    }
   
    public static boolean hasAgentBit(int mask){
        return (mask&(1<<AGENT_BIT_SHIFT))!=0;
    }
   
    public final boolean isJodbAgentObject(){
        return hasAgentBit(_secondaryDataMask);
    }
   
    public static boolean hasCyclicalCounterBit(int mask){
        return (mask&(1<<CYCLICAL_COUNTER_BIT_SHIFT))!=0;
    }
   
    public final boolean hasCyclicalCounterBit(){
        return hasCyclicalCounterBit(_secondaryDataMask);
    }
   
    public final boolean hasPrimitiveFields(){
        return hasPrimitiveFieldsBit(_primaryDataMask);
    }
   
    public static int addArrayIDBit(int mask){
        return (mask|(1<<ARRAY_ID_BIT_SHIFT));
    }
   
    public static int addTranslatedBit(int mask){
        return (mask|(1<<TRANSLATED_BIT_SHIFT));
    }
   
    public static int addAgentBit(int mask){
        return (mask|(1<<AGENT_BIT_SHIFT));
    }
   
    public static int addCyclicalCounterBit(int mask){
        return (mask|(1<<CYCLICAL_COUNTER_BIT_SHIFT));
    }
   
    public static boolean hasArrayIDBit(int mask){
        return (mask&(1<<ARRAY_ID_BIT_SHIFT))!=0;
    }
   
    public boolean isArray(){
        return hasArrayIDBit(_primaryDataMask);
    }
   
//    public boolean markAsArray(){
//        _dataMask = addArrayIDBit(_dataMask);
//    }
   
    public static int addDirectlyAddressedFieldsBit(int mask){
        return (mask|(1<<DIRECT_ADDR_BIT_SHIFT));
    }
   
    public static boolean hasDirectlyAddressedFieldsBit(int mask){
        return (mask&(1<<DIRECT_ADDR_BIT_SHIFT))!=0;
    }
   
    public boolean hasDirectlyAddressedFields(){
        return hasDirectlyAddressedFieldsBit(_primaryDataMask);
    }
   
    public static int addRelativelyAddressedFieldsID(int mask){
        return (mask|(1<<RELATIVE_ADDR_BIT_SHIFT));
    }
   
    public static boolean hasRelativelyAddressedFieldsBit(int mask){
        return (mask&(1<<RELATIVE_ADDR_BIT_SHIFT))!=0;
    }
   
    public static int addUIDFieldBit(int mask){
        return (mask|(1<<UID_BIT_SHIFT));
    }
   
    public static boolean hasUIDFieldBit(int mask){
        return (mask&(1<<UID_BIT_SHIFT))!=0;
    }
   
    public boolean hasUIDField(){
        return hasUIDFieldBit(_primaryDataMask);
    }
   
    public static int addCreationTSFieldBit(int mask){
        return (mask|(1<<CREATION_TS_BIT_SHIFT));
    }
   
    public static boolean hasCreationTSBit(int mask){
        return (mask&(1<<CREATION_TS_BIT_SHIFT))!=0;
    }
   
    public boolean hasCreationTSField(){
        return hasCreationTSBit(_primaryDataMask);
    }
   
    public static int addModificationTSFieldBit(int mask){
        return (mask|(1<<MODIFICATION_TS_BIT_SHIFT));
    }
   
    public static boolean hasModificationTSBit(int mask){
        return (mask&(1<<MODIFICATION_TS_BIT_SHIFT))!=0;
    }
   
    public boolean hasModificationTSField(){
        return hasModificationTSBit(_primaryDataMask);
    }
   
    public boolean hasRelativelyAddressedFields(){
        return hasRelativelyAddressedFieldsBit(_primaryDataMask);
    }
   
   
    private void setRedirectionOffset(long redirectionOffset) {
        _redirectionOffset = redirectionOffset;
    }
   
    public long getRedirectionOffset() {
        return _redirectionOffset;
    }
   
    public boolean isRedirection(){
        return _redirectionOffset!=-1;
    }
   
//    private void addField(int fieldID, Object value){
//        _records.add(new FieldRecord(fieldID,value));
//    }
//   
//    private void addField(int fieldID, long offset){
//        _records.add(new FieldRecord(fieldID,offset));
//    }
//   
//   
//   
//    public void getFieldsRecords(Vector<FieldRecord> result) {
//        result.addAll(_records);
//    }
   
//    public int[] getClassHierarchy() {
//        return _classHierarchy;
//    }
   
    public int getTranslatedClassType() {
        return _translatedClassType;
    }
   
//    private void setClassHierarchy(int[] classHierarchy) {
//        _classHierarchy = classHierarchy;
//    }
   
    /*package*/ void printContent(IRandomAccessDataBuffer input, IOBase base, JODBSession session, long offset, boolean followRedirection, PrintStream printStream) throws IOException{
        reset();
        readHeader(input, offset, followRedirection);
        FieldsIterator fieldsIterator=null;
        if(!isDeleted() && !isRedirection()){
            readAuxiliaryData();
            readHierarchyData(base,session);
            fieldsIterator = getFieldsIterator();
        }
        printStream.println("<<< Object Data Container: >>> "+"agent="+isJodbAgentObject());
        printStream.println("Offset ="+_offset+" total len="+getTotalLength()+" Array="+isArray()+" deleted="+_deleted);
        printStream.println("Redirection="+isRedirection()+":"+_redirectionOffset+" Redirected="+isRedirectedObject());
        printStream.println("Class Hierarchy:");
        printStream.println("original type  "+_originalClassType+" translated "+_translatedClassType);
        printStream.println("Fields:");
        //TODO restore
        for (int i = 0; fieldsIterator!=null && fieldsIterator.hasNext(); i++) {
            _recordCache.clear();
            fieldsIterator.next(_recordCache, base);
            int fieldID = _recordCache._fieldID;
            String fieldName = base.getFullFieldNameForID(fieldID);
            printStream.println("  "+fieldID+" "+fieldName+ " value="+_recordCache._value+" offset="+_recordCache._objectOffset);
        }
        printStream.println("Object Data Container: >>>");
    }
   
    private boolean isClean(){
        return _reseted;
    }
   
//    public void init(IRandomAccessDataBuffer input, long offset, boolean followRedirection) throws IOException{
//        readHeader(input, offset, followRedirection);
//    }

    /**
     *
     * @param ioTicket
     * @return true if object deleted
     * @throws IOException
     */
    public void readHeader(IOTicket ticket, boolean followRedirection) throws IOException{
        IRandomAccessDataBuffer randomAccessDataBuffer = ticket.getRandomAccessBuffer();
        readHeader(randomAccessDataBuffer, randomAccessDataBuffer.getCursorOffset(), followRedirection);
    }
   
    /**
     *
     * @param ioTicket
     * @return true if object deleted
     * @throws IOException
     */
    public void readHeader(IOTicket ticket, boolean followRedirection, Vector<IndexingRecord> indexes) throws IOException{
        IRandomAccessDataBuffer randomAccessDataBuffer = ticket.getRandomAccessBuffer();
        readHeader(randomAccessDataBuffer, randomAccessDataBuffer.getCursorOffset(), followRedirection, indexes);
    }
   
    public void readHeader(IRandomAccessDataBuffer input, long offset, boolean followRedirection) throws IOException{
        readHeader(input, offset, followRedirection, null);
    }
   
    /**
     *
     * @param ioTicket
     * @return true if object deleted
     * @throws IOException
     */
    public void readHeader(IRandomAccessDataBuffer input, long offset, boolean followRedirection, Vector<IndexingRecord> indexes) throws IOException{
        if(!isClean()){
            throw new IOException();
        }
        input.prefetch(offset);
        setOffset(offset);
        _input = input;
        _indexes = indexes;
        input.seek(offset);
        long recordStartOffset = input.getCursorOffset();
        short id = input.readShort();
        setId(id);
        long bodyLength = readEntryLen(id, input);
        long bodyStartOffset = input.getCursorOffset();
        setLength(bodyStartOffset-recordStartOffset, bodyLength);
        switch (getObjectTypeID()) {
        case JODBIOBase.ENTRY_EMPTY_ID:
            setDeleted(true);
            break;
        case JODBIOBase.ENTRY_OBJECT_ID:
            _primaryDataMask = input.readByte();
            _secondaryDataMask = input.readByte();
            if(hasCyclicalCounterBit()){
                _cyclicVersionCounter = (short) (input.readByte()&0xFF);
            }
            //setDataMask(mask);
            break;
        case JODBIOBase.ENTRY_REDIRECTOR_ID:
            long redirectionOffset = input.readLong();
            if(followRedirection){
                //input.seek(redirectionOffset);
                reset();
                readHeader(input, redirectionOffset, false);
            }else{
                setRedirectionOffset(redirectionOffset);
            }
            break;
        default:
            throw new JodbIOException("Illegal entry ID "+id);
        }
        _auxiliaryDataStartOffset = input.getCursorOffset();
        //setRemainingBytesInRecord( bodyLength - (_auxiliaryDataStartOffset - bodyStartOffset) );
    }
   
    public void readAuxiliaryData() throws IOException{
        if(_auxiliaryDataStartOffset == -1 || isDeleted() || isRedirection()){
            throw new JodbIOException("Illegal IO state");
        }
        if(_hierarchyDataStartOffset != -1){
            return;//data has been read already
        }
        _input.seek(_auxiliaryDataStartOffset);
        if (hasUIDField()) {
            long uid = _input.readLong();
            setUID(uid);
        }    
        if(hasCreationTSField()){
            long creationTS = _input.readLong();
            setCreatedTimeStamp(creationTS);
        }
        if(hasModificationTSField()){
            long modifTS = _input.readLong();
            setModificationTimeStamp(modifTS);
        }
        _hierarchyDataStartOffset = _input.getCursorOffset();
    }
   
    public void readHierarchyData(IOBase base, JODBSession session) throws IOException{
        if(_hierarchyDataStartOffset == -1 || isDeleted() || isRedirection()){
            throw new JodbIOException("Illegal IO state");
        }
        if(_objectDataStartOffset != -1){
            return;//data has been read already
        }
        _input.seek(_hierarchyDataStartOffset);
       
        _originalClassType = _input.readShort()&0xFFFF;

        if(isTranslated()){
            _translatedClassType = _input.readShort()&0xFFFF;
        }else{
            _translatedClassType = _originalClassType;
        }

        try {
            _translatedClassDescriptor = session.getDescriptorForClass(_translatedClassType);
        } catch (Exception e1) {
            //throw new IOException("reason: "+e1.getMessage()); //TODO add warning?
        }
       
//        int totalHierarchyIDs = _input.readShort()&0xFFFF;
//        int[] hierarchyIDs = new int[totalHierarchyIDs];
//        for (int i = 0; i < hierarchyIDs.length; i++) {
//            hierarchyIDs[i] = _input.readShort()&0xFFFF;
//        }
//        _classHierarchy = hierarchyIDs;
       
        _objectDataStartOffset = _input.getCursorOffset();
        if(isArray()){
            String fieldType = base.getClassTypeForID(_translatedClassType);
            _arrayType = null;
            try {
                _arrayType = Class.forName(fieldType);
            } catch (ClassNotFoundException e) {
                _arrayType = PrimitiveJavaTypesUtil.primitiveClassForName(fieldType);
                if(_arrayType == null){
                    e.printStackTrace();
                }
                //TODO debug output???
            }
        }
    }

    public FieldsIterator readObject(JODBOperationContext context, long offset, boolean followRedirection) throws IOException{
        return readObject(context.getIoTicket().getRandomAccessBuffer(), context.getBase(), context.getSession(), offset, followRedirection, null);
    }
   
    public FieldsIterator readObject(JODBOperationContext context, long offset, boolean followRedirection, Vector<IndexingRecord> indexes) throws IOException{
        return readObject(context.getIoTicket().getRandomAccessBuffer(), context.getBase(), context.getSession(), offset, followRedirection, indexes);
    }
   
    public FieldsIterator readObject(IRandomAccessDataBuffer dataBuffer, IOBase base, JODBSession session, long offset, boolean followRedirection) throws IOException{
        return readObject(dataBuffer, base, session, offset, followRedirection, null);
    }
   
    public FieldsIterator readObject(IRandomAccessDataBuffer dataBuffer, IOBase base, JODBSession session, long offset, boolean followRedirection, Vector<IndexingRecord> indexes) throws IOException{
        readHeader(dataBuffer, offset, followRedirection, indexes);
        if(isDeleted() || isRedirection()){
            resetInputSourceToEnd(base);
            return null;
        }
        readAuxiliaryData();
        readHierarchyData(base, session);
        if(isArray() && _arrayType == null){
            return null;
        }
        return getFieldsIterator();
    }
   
    private FieldsIterator getFieldsIterator() throws IOException{
        if(_translatedClassDescriptor == null){
            return null;
        }
        if(isArray()){
            _arrayFieldsIterator.init();
            _activeIterator = _arrayFieldsIterator;
            return _arrayFieldsIterator;
        }else{
            _objectFieldsIterator.init();
            _activeIterator = _objectFieldsIterator;
            return _objectFieldsIterator;
        }
    }
   
    public FieldsIterator getActiveFieldsIterator() {
        return _activeIterator;
    }
   
    private static long readEntryLen(short entryID, DataInput input) throws IOException{
        switch (entryID&(JODBIOBase.LEN_MODIFIER_BYTE|JODBIOBase.LEN_MODIFIER_LONG)) {
        case JODBIOBase.LEN_MODIFIER_BYTE:
            return input.readByte()&0xff;
        case JODBIOBase.LEN_MODIFIER_LONG:
            return input.readLong();
        case 0:
            return input.readShort()&0xffff;
        default:
            throw new JodbIOException("format error: unknown len modifier in id="+entryID);
        }
    }
   
    public void resetInputSourceToEnd(IOBase base) throws IOException{
        if (base!=null && _activeIterator!=null && _indexes !=null) {
            while (_processedIndexes < _indexes.size() && _activeIterator.hasNext()) {
                _activeIterator.next(_recordCache, base, false);
            }
        }       
        _input.seek(_offset+getTotalLength());
    }
   
    public long getEndOffset(){
        return _offset+getTotalLength();
    }
   
    public FieldRecord getRecordCache() {
        return _recordCache;
    }
   
    public ClassDescriptor getClassDescriptorForPersistedObject() {
        return _translatedClassDescriptor;
    }
   
//    public IndexingRecord getIndexingRecord(int fieldId){
//        if(_indexes == null){
//            return null;
//        }
//        for (int i = 0; i < _indexes.size() ; i++) {
//            IndexingRecord record = _indexes.elementAt(i);
//            if(record.getIndexingAgent().getClassId() == fieldId){
//                return record;
//            }
//        }
//        return null;
//    }
   
    public static class FieldRecord {
       
        public int _fieldID;
        public int _fieldTypeID;
        public String _fieldTypeName;
        public Object _value;
        public long _objectOffset;
        public ByteBuffer _primitiveRawDataBuffer = ByteBuffer.allocateDirect(16);//double the size of long, to make sure any primitive fits
        public FIELD_CATEGORIES _category;
       
        public FieldRecord() {
        }
       
        public FieldRecord(int fieldID, Object value) {
            super();
            _fieldID = fieldID;
            _value = value;
        }

        public FieldRecord(int fieldID, long objectOffset) {
            super();
            _fieldID = fieldID;
            _objectOffset = objectOffset;
        }
       
        public void clear(){
            _fieldID =-1;
            _value = null;
            _objectOffset = -1;
            _primitiveRawDataBuffer.clear();
            _category = null;
            _fieldTypeName = null;
        }
       
        @Override
        public String toString()
        {
            return ""+_fieldID+" "+_value+" "+_objectOffset;
        }
    }
   
    public interface FieldsIterator{
        boolean hasNext();       
        void next(FieldRecord record, IOBase base) throws IOException;
        void next(FieldRecord record, IOBase base, boolean unfoldPrimitive) throws IOException;
        int getRemainingInCurrentCategory();
        void reset() throws IOException;
    }
   
    public class ArrayFieldsIterator implements FieldsIterator{
       
        private long[] _slot = new long[8];//allocate read cache, max 8 londs to cache
        private int _elementLen;
        private int _indexInSlot;
        private int _remainingElementsInArray;
        private byte _currentSlotMask;
        private long _slotStartOffset;
        private long _readingOffset;
       
        private void init() throws IOException{
            if(_objectDataStartOffset == -1 || _arrayType == null || isDeleted() || isRedirection()){
                throw new JodbIOException("Illegal IO state");
            }
            _input.seek(_objectDataStartOffset);
            _remainingElementsInArray = _input.readInt();
            _elementLen = _input.readUnsignedByte();
            _indexInSlot = Integer.MAX_VALUE;
            _readingOffset = _input.getCursorOffset();
            if( !_arrayType.isPrimitive() ){
                checkNextSlot();
            }
        }
       
        private void checkNextSlot() throws IOException{
            if(_indexInSlot < 8 || _remainingElementsInArray == 0){
                return;
            }
            _input.seek(_readingOffset);
            _indexInSlot = 0;
            int maxToRead = Math.min(8, _remainingElementsInArray);
            _slotStartOffset = _input.getCursorOffset();
            for (int i = 0; i < maxToRead; i++) {
                if(_elementLen > 0xFFFFFFFFL){
                    _slot[i] = _input.readLong();
                }else{
                    _slot[i] = _input.readInt();
                }
            }
            _currentSlotMask = _input.readByte();
            _readingOffset = _input.getCursorOffset();
        }

        public final boolean hasNext() {
            return _remainingElementsInArray > 0;
        }
       
        private boolean isAbsoluteOffset(){
            return (_currentSlotMask & (1<<_indexInSlot))!=0;
        }

        public void next(FieldRecord record, IOBase base, boolean unfoldPrimitive) throws IOException {
            if(!hasNext()){
                throw new IOException();
            }
            if(_arrayType.isPrimitive()){//read primitive
                if (unfoldPrimitive) {
                    Object value = Utils.readPrimitive(_arrayType.getName(), _input);
                    record._value = value;
                }else{
                    record._primitiveRawDataBuffer.clear();
                    record._primitiveRawDataBuffer.limit(_elementLen);
                    _input.getChannel().read(record._primitiveRawDataBuffer);
                    record._primitiveRawDataBuffer.flip();
                }
                _remainingElementsInArray--;
                return;
            }
            record._objectOffset = _slot[_indexInSlot];
            if(record._objectOffset!=0 && !isAbsoluteOffset()){
                record._objectOffset+=_slotStartOffset+(_indexInSlot+1)*_elementLen;
            }
            _indexInSlot++;
            _remainingElementsInArray--;
            checkNextSlot();
        }
       
        public void next(FieldRecord record, IOBase base) throws IOException {
            next(record, base, true);
        }

        public int getRemainingInCurrentCategory() {
            return _remainingElementsInArray;
        }

        public void reset() throws IOException {
            init();
        }

    }
     
    public class ObjectFieldsIterator implements FieldsIterator{
        private FIELD_CATEGORIES _fieldsCategory;
        private int _remainingPersistentFieldsInCategory;
        private long _readingOffset;
        private BitSet _unprocessedFields = new BitSet();
       
       
        private void init() throws IOException{
            if(_objectDataStartOffset == -1 || isDeleted() || isRedirection()){
                throw new JodbIOException("Illegal IO state");
            }
            _fieldsCategory = null;
            _remainingPersistentFieldsInCategory = 0;
            _unprocessedFields.clear();
            if(_translatedClassDescriptor!=null){
                int total = _translatedClassDescriptor.getAllFields().length;
                _unprocessedFields.set(0, total);
            }
            if(_objectDataStartOffset != _offset+getTotalLength()){
                _input.seek(_objectDataStartOffset);
                checkNextCategoryNeed();
            }
        }
       
        private void checkNextCategoryNeed() throws IOException{
            while (_remainingPersistentFieldsInCategory == 0) {
                int index = _fieldsCategory == null? 0: _fieldsCategory.ordinal() + 1;
                if (index < FIELD_CATEGORIES.values().length) {
                    _fieldsCategory = FIELD_CATEGORIES.values()[index];
                    if((_primaryDataMask & (1 << index)) != 0){
                        _remainingPersistentFieldsInCategory = _input.readShort() & 0xFFFF;
                    }
                }else{
                    break;
                }
            }
            _readingOffset = _input.getCursorOffset();
        }
       
        public boolean hasNext(){
            return _unprocessedFields.cardinality()>0;
        }
       
        private boolean hasNextPersistent(){
            return _remainingPersistentFieldsInCategory!=0;
        }
       
        public void next(FieldRecord record, IOBase base) throws IOException {
            next(record, base, true);
        }
       
        public void next(FieldRecord record, IOBase base, boolean unfoldPrimitive) throws IOException {
            if(!hasNext()){
                throw new IOException();
            }
            if(hasNextPersistent())_input.seek(_readingOffset);
            boolean validRecord = false;
            while(hasNextPersistent()){
                record._fieldID = _input.readShort()&0xffff;
                String fieldID = base.getFullFieldNameForID(record._fieldID);
                record._fieldTypeID = fieldID.charAt(1);
                record._fieldTypeName = base.getClassTypeForID(record._fieldTypeID);
                record._category = _fieldsCategory;
                switch (_fieldsCategory) {
                case DIRECTLY_ADDRESSED:
                    record._objectOffset = _input.readLong();
                    break;
                case RELATIVELY_ADDRESSED:
                    record._objectOffset = _input.readInt()+_input.getCursorOffset();
                    break;
                case PRIMITIVE:
                    record._primitiveRawDataBuffer.clear();
                    IndexingRecord indexingRecord = IndexingRecord.findIndexingRecord(record._fieldID, _indexes);
                    if (unfoldPrimitive) {
                        Object value;
                        if( indexingRecord!=null ){
                            int dataLen = PrimitiveJavaTypesUtil.getDataOutputWriteLen(record._fieldTypeName);
                            record._primitiveRawDataBuffer.limit(dataLen);
                            ByteBuffer buffer = indexingRecord.getPersistedDataBuffer();
                            _input.getChannel().read(buffer);
                            buffer.flip();
                            value = PrimitiveJavaTypesUtil.getAsWrappedPrimitive( PrimitiveJavaTypesUtil.getEnumeratedType(record._fieldTypeName) , buffer);
                            _processedIndexes++;
                        }else{
                            value = Utils.readPrimitive(record._fieldTypeName, _input);
                        }
                        record._value = value;
                    }else{
                        int dataLen = PrimitiveJavaTypesUtil.getDataOutputWriteLen(record._fieldTypeName);
                        record._primitiveRawDataBuffer.limit(dataLen);
                        _input.getChannel().read(record._primitiveRawDataBuffer);
                        record._primitiveRawDataBuffer.flip();
                        if( indexingRecord!=null ){
                            indexingRecord.setPersistedDataBufferValue(record._primitiveRawDataBuffer);
                            record._primitiveRawDataBuffer.rewind();
                            _processedIndexes++;
                        }
                    }
                }
                _remainingPersistentFieldsInCategory--;
                checkNextCategoryNeed();
                if(_translatedClassDescriptor!=null){
                    int fieldIndex = _translatedClassDescriptor.getFieldIndexForID(record._fieldID);
                    if(fieldIndex == -1){//field doesn't exist in class definition
                        record.clear();
                        continue;
                    }else{
                        _unprocessedFields.clear(fieldIndex);
                    }
                }
                validRecord = true;
                break;
            }
            if(!validRecord && _translatedClassDescriptor != null){
                int nextUnrocessedIndex = _unprocessedFields.nextSetBit(0);
                if(nextUnrocessedIndex == -1){
                    throw new JodbIOException("nextUnrocessedIndex == -1)");
                }
                FieldAndIDRecord fieldAndIDRecord = _translatedClassDescriptor.getAllFields()[nextUnrocessedIndex];
                Class fieldType = fieldAndIDRecord._field.getType();
                record._fieldID = fieldAndIDRecord._id;
                IndexingRecord indexingRecord = IndexingRecord.findIndexingRecord(record._fieldID, _indexes);
                record._fieldTypeName = fieldType.getName();
                record._fieldTypeID = base.getOrSetClassTypeSubstitutionID( record._fieldTypeName );
                if(fieldType.isPrimitive()){
                    record._category = FIELD_CATEGORIES.PRIMITIVE;
                    if(unfoldPrimitive){
                        record._value = PrimitiveJavaTypesUtil.getDefaultWrapperInstance(record._fieldTypeName);
                    }else{
                        int dataLen = PrimitiveJavaTypesUtil.getDataOutputWriteLen(record._fieldTypeName);
                        record._primitiveRawDataBuffer.limit(dataLen);
                        record._primitiveRawDataBuffer.put(AUXILIARY_MAX_PRIMITIVE_CLEAN_ARRAY,0,dataLen);
                        record._primitiveRawDataBuffer.flip();
                    }
                    if(indexingRecord!=null){
                        indexingRecord.setPersistedDataBufferValue(PrimitiveJavaTypesUtil.getDefaultValueAsByteBuffer(record._fieldTypeName));
                        _processedIndexes++;
                    }
                }else{
                    record._category = FIELD_CATEGORIES.RELATIVELY_ADDRESSED;
                    record._objectOffset = 0;
                }
                _unprocessedFields.clear(nextUnrocessedIndex);
            }
           
        }
       
        public int getRemainingInCurrentCategory() {
            return _remainingPersistentFieldsInCategory;
        }

        public void reset() throws IOException {
            init();
        }
    }
}

TOP

Related Classes of com.mobixess.jodb.core.io.ObjectDataContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.