org.breizhbeans.thrift.tools.thriftmongobridge.protocol.TBSONProtocol.java Source code

Java tutorial

Introduction

Here is the source code for org.breizhbeans.thrift.tools.thriftmongobridge.protocol.TBSONProtocol.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.breizhbeans.thrift.tools.thriftmongobridge.protocol;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.codec.binary.Hex;
import org.apache.thrift.TBase;
import org.apache.thrift.TException;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.meta_data.ListMetaData;
import org.apache.thrift.meta_data.MapMetaData;
import org.apache.thrift.meta_data.SetMetaData;
import org.apache.thrift.meta_data.StructMetaData;
import org.apache.thrift.protocol.TField;
import org.apache.thrift.protocol.TList;
import org.apache.thrift.protocol.TMap;
import org.apache.thrift.protocol.TMessage;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.protocol.TSet;
import org.apache.thrift.protocol.TStruct;
import org.apache.thrift.protocol.TType;
import org.apache.thrift.transport.TTransport;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.breizhbeans.thrift.tools.thriftmongobridge.secured.TBSONSecuredWrapper;

public class TBSONProtocol extends TProtocol {
    public static final char QUOTE = '"';

    private static ThreadLocal<Stack<Context>> threadSafeContextStack = new ThreadLocal<>();
    private static ThreadLocal<DBObject> threadSafeDBObject = new ThreadLocal<>();
    private static ThreadLocal<Map<Class<?>, List<Short>>> threadSafeFieldIds = new ThreadLocal<>();
    private static ThreadLocal<TBase<?, ?>> threadSafeTBase = new ThreadLocal<>();

    private static ThreadLocal<Map<Class<?>, Map<String, ThriftField>>> threadSafeTFields = new ThreadLocal<>();

    private static TBSONSecuredWrapper tbsonSecuredWrapper = new DefaultUnsecuredWrapper();

    public static void addSecuredWrapper(TBSONSecuredWrapper tbsonSecuredWrapper) {
        TBSONProtocol.tbsonSecuredWrapper = tbsonSecuredWrapper;
    }

    public static TBSONSecuredWrapper getSecuredWrapper() {
        return TBSONProtocol.tbsonSecuredWrapper;
    }

    /**
      * Factory
      */
    public static class Factory implements TProtocolFactory {
        public TProtocol getProtocol(TTransport trans) {
            return new TBSONProtocol();
        }
    }

    /**
     * Constructor
     */
    public TBSONProtocol() {
        super(null);
    }

    public DBObject getDBObject() {
        return threadSafeDBObject.get();
    }

    public void setDBOject(DBObject dbObject) {
        threadSafeDBObject.set(dbObject);
    }

    public void setFieldIdsFilter(TBase<?, ?> base, TFieldIdEnum[] fieldIds) {
        base.getClass();
        List<Short> filteredFields = new ArrayList<>();

        for (TFieldIdEnum tFieldIdEnum : fieldIds) {
            filteredFields.add(tFieldIdEnum.getThriftFieldId());
        }
        Map<Class<?>, List<Short>> filter = new HashMap<>();
        filter.put(base.getClass(), filteredFields);
        threadSafeFieldIds.set(filter);
    }

    public void setBaseObject(TBase<?, ?> base) {
        threadSafeTBase.set(base);
    }

    private static final TStruct ANONYMOUS_STRUCT = new TStruct();
    private static final TField ANONYMOUS_FIELD = new TField();
    private static final TMessage EMPTY_MESSAGE = new TMessage();
    private static final TSet EMPTY_SET = new TSet();
    private static final TList EMPTY_LIST = new TList();
    private static final TMap EMPTY_MAP = new TMap();

    protected class ThriftField {
        public TFieldIdEnum tfieldIdEnum;
        public org.apache.thrift.meta_data.FieldMetaData fieldMetaData;

        public ThriftField(TFieldIdEnum tfieldIdEnum, org.apache.thrift.meta_data.FieldMetaData fieldMetaData) {
            this.tfieldIdEnum = tfieldIdEnum;
            this.fieldMetaData = fieldMetaData;
        }
    }

    protected abstract class Context {
        public DBObject dbObject = null;
        public DBObject securedDbObject = null;
        public Object thriftObject;
        public boolean secured = false;
        public boolean hash = false;
        public String name = null;
        public Short thriftId;

        abstract void addSecured(String value);

        abstract void add(String value);

        abstract void add(int value);

        abstract void add(long value);

        abstract void add(double value);

        abstract void add(ByteBuffer bin);

        public void addDBObject(DBObject dbObject) {
            this.dbObject = dbObject;

        }
    }

    protected class FieldContext extends Context {

        public FieldContext(String name, short thriftId, TBSONSecuredWrapper.ThriftSecuredField securedField) {
            this.name = name;
            this.thriftId = thriftId;
            this.secured = securedField.isSecured();
            this.hash = securedField.isHash();
        }

        public String name;
        public Object value;
        public Object securedValue;

        @Override
        void addSecured(String value) {
            securedValue = value;
        }

        void add(String value) {
            this.value = value;
        }

        void add(int value) {
            this.value = value;
        }

        void add(long value) {
            this.value = value;
        }

        void add(double value) {
            this.value = value;
        }

        public void add(ByteBuffer bin) {
            this.value = bin.array();
        }
    }

    // Class for all object container likes list set and maps
    protected abstract class ObjectContainerContext extends Context {
        abstract void add(DBObject value);
    }

    protected class ListContext extends ObjectContainerContext {
        BasicDBList dbList = new BasicDBList();
        Integer index = 0;

        @Override
        void addSecured(String value) {

        }

        void add(String value) {
            dbList.put(index.toString(), value);
            index++;
        }

        void add(int value) {

            dbList.put(index.toString(), Integer.valueOf(value));
            index++;
        }

        @Override
        void add(long value) {
            dbList.put(index.toString(), Long.valueOf(value));
            index++;
        }

        void add(double value) {
            dbList.put(index.toString(), Double.valueOf(value));
            index++;
        }

        @Override
        void add(ByteBuffer bin) {
            dbList.put(index.toString(), bin.array());
            index++;
        }

        void add(DBObject value) {
            dbList.put(index.toString(), value);
            index++;
        }

        Object next() {
            Object object = dbList.get(index);
            index++;
            return object;
        }
    }

    protected class MapContext extends ObjectContainerContext {
        private DBObject dbMap = new BasicDBObject();
        private byte keyType;

        public Stack<String> keyStack;
        boolean extractKey = true;

        public MapContext(byte keyType) {
            this.keyType = keyType;
        }

        public void setDbMap(DBObject dbMap) {
            this.dbMap = dbMap;
            this.keyStack = new Stack<>();
            this.keyStack.addAll(this.dbMap.keySet());
        }

        // A Map
        private String stringKey = null;

        @Override
        void addSecured(String value) {

        }

        void add(String value) {
            if (stringKey != null) {
                dbMap.put(stringKey, value);
                stringKey = null;
            } else {
                stringKey = value;
            }
        }

        @Override
        void add(int value) {
            if (stringKey != null) {
                dbMap.put(stringKey, value);
                stringKey = null;
            } else {
                stringKey = Integer.toString(value);
            }
        }

        @Override
        void add(long value) {
            if (stringKey != null) {
                dbMap.put(stringKey, value);
                stringKey = null;
            } else {
                stringKey = Long.toString(value);
            }
        }

        @Override
        void add(double value) {
            if (stringKey != null) {
                dbMap.put(stringKey, value);
                stringKey = null;
            } else {
                stringKey = Double.toString(value);
            }
        }

        @Override
        void add(ByteBuffer bin) {
            if (stringKey != null) {
                dbMap.put(stringKey, bin.array());
                stringKey = null;
            }
        }

        void add(DBObject value) {
            if (stringKey != null) {
                dbMap.put(stringKey, value);
                stringKey = null;
            }
        }

        Object next() {
            if (extractKey) {
                extractKey = false;
                return this.keyStack.firstElement();
            } else {
                extractKey = true;
                String key = this.keyStack.remove(0);
                return dbMap.get(key);
            }
        }

        public boolean isNextKey() {
            return extractKey;
        }
    }

    protected class StructContext extends Context {
        private Stack<String> fieldsStack;
        public Object thriftObject;

        public void setDbObject(DBObject dbObject) {
            this.dbObject = dbObject;
            this.fieldsStack = new Stack<String>();
            this.fieldsStack.addAll(this.dbObject.keySet());
        }

        public StructContext(String structName) {
            name = structName;
            dbObject = new BasicDBObject();
            securedDbObject = null;
        }

        @Override
        void addSecured(String value) {

        }

        @Override
        void add(String value) {
        }

        @Override
        void add(int value) {
            // Nothing to do
        }

        @Override
        void add(long value) {
            // Nothing to do
        }

        @Override
        void add(double value) {
            // Nothing to do
        }

        @Override
        void add(ByteBuffer bin) {
            // Nothing to do
        }
    }

    /**
     * Push a new write context onto the stack.
     */
    protected void pushContext(Context c) {
        Stack<Context> stack = threadSafeContextStack.get();
        if (stack == null) {
            stack = new Stack<Context>();
            stack.push(c);
            threadSafeContextStack.set(stack);
        } else {
            threadSafeContextStack.get().push(c);
        }
    }

    protected boolean isContextEmpty() {
        Stack<Context> stack = threadSafeContextStack.get();
        if (stack == null || stack.size() == 0) {
            return true;
        }
        return false;
    }

    /**
     * Pop the last write context off the stack
     */
    protected Context popContext() {
        return threadSafeContextStack.get().pop();
    }

    protected Context peekContext() {
        return threadSafeContextStack.get().peek();
    }

    public void writeMessageBegin(TMessage message) throws TException {
        // trans_.write(LBRACKET);
        pushContext(new ListContext());
    }

    public void writeMessageEnd() throws TException {
        popContext();
    }

    public void writeStructBegin(TStruct struct) throws TException {
        StructContext c = new StructContext(struct.name);
        pushContext(c);
    }

    public void writeStructEnd() throws TException {
        // Gets the struct
        Context ctx = popContext();
        DBObject dbObject = ctx.dbObject;

        if (ctx.securedDbObject != null) {
            dbObject.put("securedwrap", ctx.securedDbObject);
        }

        // Sets the DBObject for output
        threadSafeDBObject.set(dbObject);

        // if the stack is not empty add the struct current stack field
        if (!isContextEmpty()) {
            Context fieldContext = peekContext();

            // For the ListContext adds the strcut to the context
            if (fieldContext instanceof ObjectContainerContext) {
                ((ObjectContainerContext) fieldContext).add(dbObject);
            } else {
                // Thrift general field adds the object to the field
                fieldContext.addDBObject(dbObject);
            }
        }
    }

    public void writeFieldBegin(TField field) throws TException {
        // Note that extra type information is omitted in BSON!
        Context ctx = peekContext();
        //TBSONSecuredWrapper.ThriftSecuredField securedField=tbsonSecuredWrapper.getField(ctx.name, field.id);
        TBSONSecuredWrapper.ThriftSecuredField securedField = tbsonSecuredWrapper.getField(null, field.id);

        if (securedField.isSecured() && ctx.securedDbObject == null) {
            ctx.securedDbObject = new BasicDBObject();
        }

        pushContext(new FieldContext(field.name, field.id, securedField));
    }

    public void writeFieldEnd() throws TException {
        Context c = popContext();
        Context dbObjectContext = peekContext();
        if (c.dbObject == null) {
            dbObjectContext.dbObject.put(((FieldContext) c).name, ((FieldContext) c).value);
            if (dbObjectContext.securedDbObject != null) {
                dbObjectContext.securedDbObject.put(((FieldContext) c).thriftId.toString(),
                        ((FieldContext) c).securedValue);
            }
        } else {
            dbObjectContext.dbObject.put(((FieldContext) c).name, c.dbObject);
        }
    }

    public void writeFieldStop() {
    }

    public void writeMapBegin(TMap map) throws TException {
        MapContext c = new MapContext(map.keyType);
        pushContext(c);
    }

    public void writeMapEnd() throws TException {
        // Gets the map
        MapContext map = (MapContext) popContext();
        // Add the map to the current field
        Context fieldContext = peekContext();
        fieldContext.addDBObject(map.dbMap);
    }

    public void writeListBegin(TList list) throws TException {
        pushContext(new ListContext());
    }

    public void writeListEnd() throws TException {
        // Gets the list
        ListContext list = (ListContext) popContext();
        // Add the list to the current field
        Context fieldContext = peekContext();
        fieldContext.addDBObject(list.dbList);
    }

    /**
     * A Set have the same serialization of a thrift List
     */
    public void writeSetBegin(TSet set) throws TException {
        pushContext(new ListContext());
    }

    /**
     * A Set have the same serialization of a thrift List
     */
    public void writeSetEnd() throws TException {
        // Gets the list
        ListContext list = (ListContext) popContext();
        // Add the list to the current field
        Context fieldContext = peekContext();
        fieldContext.addDBObject(list.dbList);
    }

    public void writeBool(boolean b) throws TException {
        writeByte(b ? (byte) 1 : (byte) 0);
    }

    public void writeByte(byte b) throws TException {
        peekContext().add((int) b);
    }

    public void writeI16(short i16) throws TException {
        peekContext().add((int) i16);
    }

    public void writeI32(int i32) throws TException {
        peekContext().add(i32);
    }

    public void writeI64(long i64) throws TException {
        peekContext().add(i64);
    }

    public void writeDouble(double dub) throws TException {
        peekContext().add(dub);
    }

    public void writeString(String str) throws TException {
        try {
            Context context = peekContext();

            if (context.secured) {
                // compute hash from the value if needed
                if (context.hash) {
                    context.add(new Long(TBSONProtocol.tbsonSecuredWrapper.digest64(str.getBytes("UTF-8"))));
                }
                // crypt the value and add it to the secured field
                context.addSecured(
                        Hex.encodeHexString(TBSONProtocol.tbsonSecuredWrapper.cipher(str.getBytes("UTF-8"))));
            } else {
                context.add(new String(str.getBytes("UTF-8")));
            }
        } catch (UnsupportedEncodingException uex) {
            throw new TException("JVM DOES NOT SUPPORT UTF-8");
        }
    }

    public void writeBinary(ByteBuffer bin) throws TException {
        peekContext().add(bin);
    }

    /**
     * Reading methods.
     */

    public TMessage readMessageBegin() throws TException {
        return EMPTY_MESSAGE;
    }

    public void readMessageEnd() {
    }

    public TStruct readStructBegin() throws TException {
        try {
            DBObject dbObject = null;
            Object thriftObject = null;

            if (!isContextEmpty()) {
                Context currentContext = peekContext();

                if (currentContext instanceof ListContext) {
                    dbObject = (DBObject) ((ListContext) currentContext).next();
                    thriftObject = ((ListContext) peekContext()).thriftObject;
                } else if (currentContext instanceof MapContext) {
                    dbObject = (DBObject) ((MapContext) currentContext).next();
                    thriftObject = ((MapContext) peekContext()).thriftObject;
                } else {
                    return ANONYMOUS_STRUCT;
                }
            } else {
                thriftObject = threadSafeTBase.get();
                dbObject = getDBObject();
            }
            StructContext context = new StructContext(thriftObject.getClass().getSimpleName());
            context.setDbObject(dbObject);
            context.thriftObject = thriftObject;
            pushContext(context);

            return ANONYMOUS_STRUCT;
        } catch (Exception exp) {
            throw new TException("Unexpected readStructBegin", exp);
        }
    }

    public void readStructEnd() {
        popContext();
    }

    public TField readFieldBegin() throws TException {
        StructContext context = (StructContext) peekContext();
        if (context.fieldsStack.isEmpty()) {
            // Empty stack -> returns a TType.STOP
            return new TField();
        }
        String fieldName = context.fieldsStack.peek();

        TField currentField = getTField(context.thriftObject, fieldName);
        //currentField.id
        // IF the field is skiped change the type to void
        Map<Class<?>, List<Short>> filter = threadSafeFieldIds.get();

        if (filter != null) {
            List<Short> fieldsFiltered = filter.get(context.thriftObject.getClass());
            if (fieldsFiltered != null && fieldsFiltered.contains(currentField.id)) {
                return new TField(currentField.name, TType.VOID, currentField.id);
            }
        }

        // If the field is a struct push a struct context in the stack
        if (currentField.type == TType.STRUCT) {
            StructContext structContext = new StructContext(fieldName);
            structContext.setDbObject((DBObject) context.dbObject.get(fieldName));
            structContext.thriftObject = getThriftObject(context.thriftObject, fieldName);
            pushContext(structContext);
        }
        return currentField;
    }

    private Object getThriftObject(Object thriftObject, String fieldName) throws TException {
        try {
            Map<String, ThriftField> classFields = getClassFields(thriftObject);
            ThriftField thriftField = classFields.get(fieldName);

            if (thriftField != null) {
                switch (thriftField.fieldMetaData.valueMetaData.type) {
                case TType.LIST:
                    ListMetaData listMetaData = (ListMetaData) thriftField.fieldMetaData.valueMetaData;
                    if (listMetaData.elemMetaData.isStruct()) {
                        return ((StructMetaData) listMetaData.elemMetaData).structClass.newInstance();
                    }
                    return null;
                case TType.SET:
                    SetMetaData setMetaData = (SetMetaData) thriftField.fieldMetaData.valueMetaData;
                    if (setMetaData.isStruct()) {
                        return ((StructMetaData) setMetaData.elemMetaData).structClass.newInstance();
                    }
                    return null;
                case TType.MAP:
                    MapMetaData mapMetaData = (MapMetaData) thriftField.fieldMetaData.valueMetaData;
                    if (mapMetaData.valueMetaData.isStruct()) {
                        return ((StructMetaData) mapMetaData.valueMetaData).structClass.newInstance();
                    }
                    return null;
                case TType.STRUCT:
                    return ((StructMetaData) thriftField.fieldMetaData.valueMetaData).structClass.newInstance();
                }
            }
            throw new Exception("FieldName not finded name=" + fieldName);
        } catch (Exception exp) {
            throw new TException("Unexpected getListThriftObject fieldName=" + fieldName, exp);
        }
    }

    private Map<String, ThriftField> getClassFields(Object thriftObject) throws TException {
        try {
            Map<Class<?>, Map<String, ThriftField>> thriftFields = threadSafeTFields.get();

            if (thriftFields == null) {
                thriftFields = new HashMap<>();
            }

            Class<?> tbase = thriftObject.getClass();
            Map<String, ThriftField> classTFields = thriftFields.get(tbase);

            if (classTFields != null) {
                return classTFields;
            }

            classTFields = new HashMap<>();

            Field metafaField = thriftObject.getClass().getField("metaDataMap");
            Map<?, org.apache.thrift.meta_data.FieldMetaData> fields = (Map<?, org.apache.thrift.meta_data.FieldMetaData>) metafaField
                    .get(thriftObject);
            // recurse on all sub structures
            for (Entry<?, org.apache.thrift.meta_data.FieldMetaData> entry : fields.entrySet()) {
                TFieldIdEnum field = (TFieldIdEnum) entry.getKey();
                classTFields.put(field.getFieldName(), new ThriftField(field, entry.getValue()));
            }

            thriftFields.put(tbase, classTFields);

            threadSafeTFields.set(thriftFields);
            return classTFields;
        } catch (Exception exp) {
            throw new TException("Unexpected object", exp);
        }
    }

    private TField getTField(Object thriftObject, String fieldName) throws TException {
        try {
            Map<String, ThriftField> classFields = getClassFields(thriftObject);
            ThriftField thriftField = classFields.get(fieldName);

            if (thriftField == null) {
                // Empty field -> skip
                return new TField();
            }

            byte type = thriftField.fieldMetaData.valueMetaData.type;
            short id = thriftField.tfieldIdEnum.getThriftFieldId();

            // An enum type is deserialized as an I32
            if (TType.ENUM == type) {
                type = TType.I32;
            }

            return new TField("", type, id);
        } catch (Exception exp) {
            throw new TException("Unexpected getTField fieldName=" + fieldName, exp);
        }
    }

    public void readFieldEnd() {
        StructContext context = (StructContext) peekContext();
        if (!context.fieldsStack.isEmpty()) {
            context.fieldsStack.pop();
        }
    }

    public TMap readMapBegin() throws TException {
        StructContext context = (StructContext) peekContext();
        if (context.fieldsStack.isEmpty()) {
            return EMPTY_MAP;
        }
        String fieldName = context.fieldsStack.peek();

        MapContext mapContext = new MapContext(TType.VOID);
        BasicDBObject dbMap = (BasicDBObject) context.dbObject.get(fieldName);

        mapContext.setDbMap(dbMap);
        mapContext.thriftObject = getThriftObject(context.thriftObject, fieldName);
        pushContext(mapContext);
        return new TMap(TType.STRING, TType.STRING, dbMap.size());
    }

    public void readMapEnd() {
        popContext();
    }

    public TList readListBegin() throws TException {
        StructContext context = (StructContext) peekContext();
        if (context.fieldsStack.isEmpty()) {
            return EMPTY_LIST;
        }
        String fieldName = context.fieldsStack.peek();

        ListContext listContext = new ListContext();
        BasicDBList dbList = (BasicDBList) context.dbObject.get(fieldName);

        listContext.dbList = dbList;
        listContext.thriftObject = getThriftObject(context.thriftObject, fieldName);
        pushContext(listContext);
        return new TList(TType.LIST, dbList.size());
    }

    public void readListEnd() {
        popContext();
    }

    public TSet readSetBegin() throws TException {
        StructContext context = (StructContext) peekContext();
        if (context.fieldsStack.isEmpty()) {
            return EMPTY_SET;
        }
        String fieldName = context.fieldsStack.peek();

        ListContext listContext = new ListContext();
        BasicDBList dbList = (BasicDBList) context.dbObject.get(fieldName);

        listContext.dbList = dbList;
        listContext.thriftObject = getThriftObject(context.thriftObject, fieldName);
        pushContext(listContext);
        return new TSet(TType.SET, dbList.size());
    }

    public void readSetEnd() {
        popContext();
    }

    public boolean readBool() throws TException {
        return (readByte() == 1);
    }

    public byte readByte() throws TException {
        return ((Number) getCurrentFieldValue(TType.BYTE)).byteValue();
    }

    public short readI16() throws TException {
        return ((Number) getCurrentFieldValue(TType.I16)).shortValue();
    }

    public int readI32() throws TException {
        return ((Number) getCurrentFieldValue(TType.I32)).intValue();
    }

    public long readI64() throws TException {
        return ((Number) getCurrentFieldValue(TType.I64)).longValue();
    }

    public double readDouble() throws TException {
        return ((Number) getCurrentFieldValue(TType.DOUBLE)).doubleValue();
    }

    public String readString() throws TException {
        return (String) getCurrentFieldValue();
    }

    private Object getCurrentFieldValue() {
        Context context = peekContext();
        if (context instanceof StructContext && ((StructContext) context).fieldsStack.isEmpty() == false) {
            String fieldName = ((StructContext) context).fieldsStack.peek();
            // Extracts the dbobject
            return context.dbObject.get(fieldName);
        } else if (context instanceof ListContext) {
            return ((ListContext) context).next();
        } else if (context instanceof MapContext) {

            // IF YOU READ A KEY YOU MUST CONVERT THE STRING INTO NUMBER

            return ((MapContext) context).next();
        }
        return null;
    }

    private Object getCurrentFieldValue(byte ttype) {
        Context context = peekContext();
        if (context instanceof StructContext && ((StructContext) context).fieldsStack.isEmpty() == false) {
            String fieldName = ((StructContext) context).fieldsStack.peek();
            // Extracts the dbobject
            Object fieldReaded = context.dbObject.get(fieldName);
            return fieldReaded;
        } else if (context instanceof ListContext) {
            return ((ListContext) context).next();
        } else if (context instanceof MapContext) {

            // IF YOU READ A KEY YOU MUST CONVERT THE STRING INTO NUMBER
            if (((MapContext) context).isNextKey()) {
                switch (ttype) {
                case TType.BYTE:
                    return Byte.parseByte((String) ((MapContext) context).next());
                case TType.I32:
                case TType.I16:
                    return Integer.parseInt((String) ((MapContext) context).next());
                case TType.I64:
                    return Long.parseLong((String) ((MapContext) context).next());
                case TType.DOUBLE:
                    return Double.parseDouble((String) ((MapContext) context).next());
                }
            }

            return ((MapContext) context).next();
        }
        return null;
    }

    public String readStringBody(int size) throws TException {
        return "";
    }

    public ByteBuffer readBinary() throws TException {
        return ByteBuffer.wrap((byte[]) getCurrentFieldValue());
    }

    public void reset() {
        threadSafeContextStack.remove();
        threadSafeDBObject.remove();
        threadSafeFieldIds.remove();
    }
}