Package org.nustaq.serialization.coders

Source Code of org.nustaq.serialization.coders.FSTMinBinDecoder

package org.nustaq.serialization.coders;

import org.nustaq.serialization.FSTClazzInfo;
import org.nustaq.serialization.FSTConfiguration;
import org.nustaq.serialization.FSTDecoder;
import org.nustaq.serialization.FSTObjectOutput;
import org.nustaq.serialization.minbin.MBIn;
import org.nustaq.serialization.minbin.MBObject;
import org.nustaq.serialization.minbin.MinBin;
import org.nustaq.serialization.util.FSTUtil;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.util.HashMap;

/**
* Copyright (c) 2012, Ruediger Moeller. All rights reserved.
* <p/>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p/>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
* <p/>
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301  USA
* <p/>
* Date: 02.04.2014
* Time: 19:13
*
* Deserializes from self describing binary MinBin format
*/
public class FSTMinBinDecoder implements FSTDecoder {
   
    FSTConfiguration conf;
    MBIn input;
    private InputStream inputStream;

    public FSTMinBinDecoder(FSTConfiguration conf) {
        this.conf = conf;
        input = new MBIn(null,0);
    }

    @Override
    public String readStringUTF() throws IOException {
        Object read = input.readObject();
        if (read instanceof String)
            return (String) read;
        // in case preceding atom has been consumed b[] => str 8 char[] => str 16;
        if (read instanceof byte[]) {
            return new String((byte[]) read, 0, 0, ((byte[]) read).length);
        } else if (read instanceof char[]) {
            return new String((char[]) read, 0, ((char[]) read).length);
        } else if (MinBin.END_MARKER == read) {
            return null;
        } else if ( read == null )
            return null;
        throw new RuntimeException("Expected String, byte[], char[] or tupel end");
    }

    @Override
    public String readStringAsc() throws IOException {
        return (String) input.readObject();
    }

    @Override
    /**
     * if array is null => create own array. if len == -1 => use len read
     */
    public Object readFPrimitiveArray(Object array, Class componentType, int len) {
        if ( componentType == double.class ) {
            double[] da = (double[]) array;
            for (int i = 0; i < da.length; i++) {
                da[i] = (double) input.readTag(input.readIn());
            }
            return da;
        }
        if ( componentType == float.class ) {
            float[] da = (float[]) array;
            for (int i = 0; i < da.length; i++) {
                da[i] = (float) input.readTag(input.readIn());
            }
            return da;
        }
        Object arr = array; // input.readObject();
        int length = Array.getLength(arr);
        if ( len != -1 && len != length)
            throw new RuntimeException("unexpected arrays size");
        byte type = 0;
        if (componentType == boolean.class)    type |= MinBin.INT_8;
        else if (componentType == byte.classtype |= MinBin.INT_8;
        else if (componentType == short.class) type |= MinBin.INT_16;
        else if (componentType == char.classtype |= MinBin.INT_16 | MinBin.UNSIGN_MASK;
        else if (componentType == int.class)   type |= MinBin.INT_32;
        else if (componentType == long.classtype |= MinBin.INT_64;
        else throw new RuntimeException("unsupported type " + componentType.getName());
        input.readArrayRaw(type,len,array);
        return arr;
    }

    @Override
    public void readFIntArr(int len, int[] arr) throws IOException {
        int res[] = (int[]) input.readObject();
        for (int i = 0; i < len; i++) {
              arr[i] = res[i];
        }
    }

    @Override
    public int readFInt() throws IOException {
        return (int) input.readInt();
    }

    @Override
    public double readFDouble() throws IOException {
        return (double) input.readObject();
    }

    @Override
    public float readFFloat() throws IOException {
        return (float) input.readObject();
    }

    @Override
    public byte readFByte() throws IOException {
        return (byte) input.readInt();
    }

    @Override
    public long readFLong() throws IOException {
        return input.readInt();
    }

    @Override
    public char readFChar() throws IOException {
        return (char) input.readInt();
    }

    @Override
    public short readFShort() throws IOException {
        return (short) input.readInt();
    }

    @Override
    public int readPlainInt() throws IOException {
        throw new RuntimeException("not supported");
    }

    @Override
    public byte[] getBuffer() {
        return input.getBuffer();
    }

    @Override
    public int getInputPos() {
        return input.getPos();
    }

    @Override
    public void moveTo(int position) {
        throw new RuntimeException("not supported");
    }

    @Override
    public void setInputStream(InputStream in) {
        this.inputStream = in;
        if ( in != null ) {
            try {
                int count = 0;
                int chunk_size = 1000;
                byte buf[] = input.getBuffer();
                if (buf==null) {
                    buf = new byte[chunk_size];
                }
                int read = in.read(buf);
                count+=read;
                while( read != -1 ) {
                    try {
                        if ( buf.length < count+chunk_size ) {
                            byte tmp[] = new byte[buf.length*2];
                            System.arraycopy(buf,0,tmp,0,count);
                            buf = tmp;
                        }
                        read = in.read(buf,count,chunk_size);
                        if ( read > 0 )
                            count += read;
                    } catch ( IndexOutOfBoundsException iex ) {
                        read = -1; // many stream impls break contract
                    }
                }
                in.close();
                input.setBuffer(buf, count);
            } catch (IOException e) {
                throw FSTUtil.rethrow(e);
            }           
        }
    }

    @Override
    public void ensureReadAhead(int bytes) {
    }

    @Override
    public void reset() {
        input.reset();
    }

    @Override
    public void resetToCopyOf(byte[] bytes, int off, int len) {
        if (off != 0 )
            throw new RuntimeException("not supported");
        input.setBuffer(bytes,len);
    }

    @Override
    public void resetWith(byte[] bytes, int len) {
        input.setBuffer(bytes,len);
    }

    public int getObjectHeaderLen() // len field of last header read (if avaiable)
    {
        if ( lastObjectLen < 0 )
            return (int) input.readInt();
        return lastObjectLen;
    }

    int lastObjectLen;
    Class lastDirectClass;
    public byte readObjectHeaderTag() throws IOException {
        lastObjectLen = -1;
        byte tag = input.peekIn();
        lastDirectClass = null;
        if ( MinBin.isTag(tag) ) {
            if ( MinBin.getTagId(tag) == MinBin.HANDLE ) {
                input.readIn(); // consume
                return FSTObjectOutput.HANDLE;
            }
            if ( MinBin.getTagId(tag) == MinBin.STRING )
                return FSTObjectOutput.STRING;
            if ( MinBin.getTagId(tag) == MinBin.BOOL ) {
                Boolean b = (Boolean) input.readObject();
                return b ? FSTObjectOutput.BIG_BOOLEAN_TRUE : FSTObjectOutput.BIG_BOOLEAN_FALSE;
            }
            if (    MinBin.getTagId(tag) == MinBin.DOUBLE ||
                    MinBin.getTagId(tag) == MinBin.DOUBLE_ARR ||
                    MinBin.getTagId(tag) == MinBin.FLOAT_ARR ||
                    MinBin.getTagId(tag) == MinBin.FLOAT
            )
            {
                lastReadDirectObject = input.readObject();
                return FSTObjectOutput.DIRECT_OBJECT;
            }
            input.readIn();
            if (MinBin.getTagId(tag) == MinBin.SEQUENCE) {
                try {
                    String cln = (String) input.readObject();
//                  client should use explicit sequence constructor
//                    if ( cln == null ) {
//                        lastDirectClass = MBSequence.class;
//                        // fast terminate as assume js object array so no int for len there ..
//                        return FSTObjectOutput.OBJECT;
//                    } else
                    {
                        lastDirectClass = conf.getClassRegistry().classForName(conf.getClassForCPName(cln));
                    }
                } catch (ClassNotFoundException e) {
                    throw FSTUtil.rethrow(e);
                }
                if ( lastDirectClass.isEnum() ) {
                    input.readInt(); // consume length of 1
                    String enumString = (String) input.readObject();
                    lastReadDirectObject = Enum.valueOf(lastDirectClass,enumString);
                    lastDirectClass = null;
                    return FSTObjectOutput.DIRECT_OBJECT;
                } else
                if ( lastDirectClass.isArray() )
                    return FSTObjectOutput.ARRAY;
                else {
                    input.readInt(); // consume -1 for unknown sequence length
                    return FSTObjectOutput.OBJECT; // with serializer
                }
            }
            if (MinBin.getTagId(tag)==MinBin.NULL)
                return FSTObjectOutput.NULL;
            return FSTObjectOutput.OBJECT;
        }
        lastReadDirectObject = input.readObject();
        return FSTObjectOutput.DIRECT_OBJECT;
    }
   
    public Object getDirectObject() // in case class already resolves to read object (e.g. mix input)
    {
        Object tmp = lastReadDirectObject;
        lastReadDirectObject = null;
        return tmp;
    }

    Object lastReadDirectObject; // in case readClass already reads full minbin value
    @Override
    public FSTClazzInfo readClass() throws IOException, ClassNotFoundException {
        if (lastDirectClass != null ) {
            FSTClazzInfo clInfo = conf.getCLInfoRegistry().getCLInfo(lastDirectClass);
            lastDirectClass = null;
            return clInfo;
        }
        Object read = input.readObject();
        String name = (String) read;
        String clzName = conf.getClassForCPName(name);
        return conf.getCLInfoRegistry().getCLInfo(classForName(clzName));
    }

    HashMap<String,Class> clzCache = new HashMap<>();
    @Override
    public Class classForName(String name) throws ClassNotFoundException {
        if ("Object".equals(name))
            return MBObject.class;
        Class aClass = clzCache.get(name);
        if (aClass!=null)
            return aClass;
        aClass = Class.forName(name);
        clzCache.put(name,aClass);
        return aClass;
    }

    @Override
    public void registerClass(Class possible) {
        throw new RuntimeException("not implemented");
    }

    @Override
    public void close() {
        //TODO
        throw new RuntimeException("not implemented");
    }

    @Override
    public void skip(int n) {
        throw new RuntimeException("not implemented");
    }

    @Override
    public void readPlainBytes(byte[] b, int off, int len) {
        for (int i = 0; i < len; i++) {
            b[i+off] = input.readIn();
        }
    }

    @Override
    public boolean isMapBased() {
        return true;
    }

    public void consumeEndMarker() {
        byte type = input.peekIn();
        if (type==MinBin.END) {
            input.readIn();
        }
    }

    @Override
    public Class readArrayHeader() throws Exception {
        byte tag = input.peekIn(); // need to be able to consume MinBin Sequence tag silently
        if ( MinBin.getTagId(tag) == MinBin.NULL ) {
            input.readIn();
            lastDirectClass = null;
            return null;
        }
        if ( lastDirectClass != null )
            return readClass().getClazz();
        if ( MinBin.getTagId(tag) == MinBin.SEQUENCE ) {
            input.readIn(); // consume (multidim array)
        } else if ( MinBin.isPrimitive(tag) ) {
            input.readIn(); // consume tag
            switch (MinBin.getBaseType(tag)) {
                case MinBin.INT_8:
                    return byte[].class;
                case MinBin.INT_16:
                    if (MinBin.isSigned(tag) )
                        return short[].class;
                    return char[].class;
                case MinBin.INT_32:
                    return int[].class;
                case MinBin.INT_64:
                    return long[].class;
            }
        }
        return readClass().getClazz();
    }

    @Override
    public void readExternalEnd() {
        if ( input.peekIn() == MinBin.END ) {
            input.readIn();
        }
    }

    @Override
    public boolean isEndMarker(String s) {
        return MinBin.END_MARKER == s;
    }

    @Override
    public int readVersionTag() throws IOException {
        return 0; // versioning not supported for minbin
    }

}
TOP

Related Classes of org.nustaq.serialization.coders.FSTMinBinDecoder

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.