view src/main/java/alice/datasegment/ReceiveData.java @ 650:4289b232b3fd

nulValue
author suruga
date Fri, 02 Feb 2018 18:26:49 +0900
parents b8527d1032c4
children 058bff2123c8
line wrap: on
line source

package alice.datasegment;

import java.io.*;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.zip.*;

import org.msgpack.MessagePack;
import org.msgpack.type.NilValue;
import org.msgpack.type.Value;


/**
 * 送られてきたDSを一時的に取っておくクラス。inputでも使用。
 */
public class ReceiveData {
    private Object val;//for Object DS
    private byte[] messagePack;//for byteArray(serialized) DS
    private byte[] zMessagePack;//for byteArray(compressed) DS
    private int dataSize;//圧縮前(MessagePack)のデータサイズ
    private Class<?> clazz;

    private long time;//測定用
    private boolean setTime = false;
    private int depth = 1;
    private boolean setZepped = false;
    private int zippedDataSize;//圧縮後のデータサイズ

    private static final MessagePack packer = new MessagePack();

    /**
     * コンストラクタ。Object型のDSと圧縮のメタ情報を受け取る。
     * put/update/reply用?
     * @param obj DS本体(Object)
     */
    public ReceiveData(Object obj) {
        if (obj == null) {
            clazz = NilValue.class;
        } else {
            clazz = obj.getClass();
        }
        val = obj;
    }

    /**
     * コンストラクタ。byteArray型のDSと圧縮のメタ情報を受け取り、byteArrayフラグを立てる。
     *
     * @param messagePack DS本体(byteArray)
     */
    public ReceiveData(byte[] messagePack, boolean compressed, int datasize) {
        this.dataSize = datasize;
        if (compressed){
            this.zMessagePack = messagePack;
        } else {
            this.messagePack = messagePack;
        }
    }

    public boolean isByteArray(){
        return messagePack != null | zMessagePack != null;
    }

    public boolean compressed(){
        return zMessagePack != null;
    }

    public boolean serialized(){
        return val == null;
    }

    public Object getObj(){
        return asClass(Object.class);
    }

    public String asString(){
        return asClass(String.class);
    }

    public int asInteger() {
        return asClass(Integer.class);
    }

    public Float asFloat() {
        return asClass(Float.class);
    }

    public Value getVal(){///get DS as Value type
        if (val == null){///val != null
            return null;
        } else {
            try {
                return packer.unconvert(val);///convert to Value type by MassagePack
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    /**
     * DSを任意の型で取得するメソッド。
     * DSがbyteArrayでなければ指定された型に変換して返す。
     * DSがbyteArrayなら解凍状態にして指定された型に変換して返す。
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T asClass(Class<T> clazz) {///javasist

        try {
            if (val != null) {
                return (T) val;
            }

            if (zMessagePack != null && messagePack == null) {
                messagePack = unzip(zMessagePack, dataSize);
            }

            return packer.read(messagePack, clazz);

        } catch (IOException e) {// | DataFormatException e
            e.printStackTrace();
            return null;
        }
    }

    public byte[] getMessagePack(){
        if (messagePack != null){
            return messagePack;
        } else {
            try {
                messagePack = packer.write(val);
                setDataSize(messagePack.length);
            } catch (IOException e) {
                e.printStackTrace();
            }

            return messagePack;
        }
    }

    public byte[] getZMessagePack(){
        if (zMessagePack != null){
            return zMessagePack;
        } else {
            try {
                zip();

            } catch (IOException e) {
                e.printStackTrace();
            }

            return zMessagePack;
        }
    }

    public void zip() throws IOException {
        LinkedList<ByteBuffer> inputs = new LinkedList<ByteBuffer>();
        int inputIndex = 0;
        LinkedList<ByteBuffer> outputs = new LinkedList<ByteBuffer>();
        Deflater deflater = new Deflater();

        inputs.add(ByteBuffer.wrap(getMessagePack()));
        int len = 0;
        int INFLATE_BUFSIZE = 1024 * 100;//ToDo:fix
        ByteBuffer c1 = allocate(INFLATE_BUFSIZE);//for output

        while (inputIndex < inputs.size()) {
            ByteBuffer b1 = inputs.get(inputIndex++);
            deflater.setInput(b1.array(), b1.position(), b1.remaining());
            
            if (inputIndex == inputs.size()){
                deflater.finish();
            }

            int len1 = 0;
            do {
                len1 = deflater.deflate(c1.array(), c1.position(), c1.remaining());
                if (len1 > 0) {
                    len += len1;
                    c1.position(c1.position() + len1);
                    if (c1.remaining() == 0) {
                        c1.flip();
                        outputs.addLast(c1);
                        c1 = allocate(INFLATE_BUFSIZE);
                    }
                }
            } while (len1 > 0 || !deflater.needsInput());
        }
        if (c1.position() != 0) {
            c1.flip();
            outputs.addLast(c1);
        }

        deflater.reset();

        zMessagePack = new byte[len];
        int tmp = 0;
        for (int i = 0; i < outputs.size(); i++){
            System.arraycopy(outputs.get(i).array(), 0, zMessagePack, 0 + tmp, outputs.get(i).limit());//limit? remaining?
            tmp += outputs.get(i).limit();
        }
    }

    protected byte[] unzip(byte[] input, int dataSize) {///read header & unzip
        int length = input.length;
        Inflater inflater = new Inflater();

        byte [] output = new byte [dataSize];///byteArray for unziped data
        inflater.setInput(input, 0, length);///set unzip data without header

        try {
            inflater.inflate(output, 0, dataSize);///unzip
        } catch (DataFormatException e) {
            e.printStackTrace();
        }

        inflater.reset();

        return output;
 	}


    public ByteBuffer allocate(int size)
    {
        ByteBuffer b = null;
        while(true){
            try {
                b = ByteBuffer.allocate(size);
            } catch (OutOfMemoryError e) {
                b = null;
            }
            if (b!=null) {
                break;
            }
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        return b;
    }


    public int getDataSize(){
        return this.dataSize;
    }

    public void setDataSize(int datasize){
        this.dataSize = datasize;
    }

    public void setTimes(long time, boolean setTime, int depth){
        this.time = time;
        this.setTime = setTime;
        this.depth = depth;
    }

    public long getTime(){
        return this.time;
    }

    public boolean getSetTime(){
        return this.setTime;
    }

    public  int getDepth(){
        return this.depth;
    }

    public  void setZipped(int zippedDataSize, boolean setZepped){
        this.zippedDataSize = zippedDataSize;
        this.setZepped = setZepped;
    }

    public  int getZippedDataSize(){
        return this.zippedDataSize;
    }

    public boolean getSetZipped(){
        return this.setZepped;
    }

}