divconq.ctp.stream.SplitStream.java Source code

Java tutorial

Introduction

Here is the source code for divconq.ctp.stream.SplitStream.java

Source

/* ************************************************************************
#
#  DivConq
#
#  http://divconq.com/
#
#  Copyright:
#    Copyright 2014 eTimeline, LLC. All rights reserved.
#
#  License:
#    See the license.txt file in the project's top-level directory for details.
#
#  Authors:
#    * Andy White
#
************************************************************************ */
package divconq.ctp.stream;

import java.util.ArrayList;
import java.util.List;

import io.netty.buffer.ByteBuf;
import divconq.ctp.f.FileDescriptor;
import divconq.script.StackEntry;
import divconq.util.FileUtil;
import divconq.util.StringUtil;
import divconq.xml.XElement;

public class SplitStream extends BaseStream implements IStreamSource {
    protected int seqnum = 1;
    protected int size = 10 * 1024 * 1024;
    protected String template = "file-%seq%.bin";

    protected int currchunk = 0;
    protected FileDescriptor sfile = null;
    protected List<FileDescriptor> outlist = new ArrayList<>();
    protected List<ByteBuf> outbuf = new ArrayList<>();

    public SplitStream() {
    }

    @Override
    public void init(StackEntry stack, XElement el) {
        this.seqnum = (int) stack.intFromElement(el, "StartAt", this.seqnum);

        String size = stack.stringFromElement(el, "Size", "10MB");

        this.size = (int) FileUtil.parseFileSize(size);

        String temp = stack.stringFromElement(el, "Template");

        if (StringUtil.isNotEmpty(temp))
            this.template = temp;
    }

    // make sure we don't return without first releasing the file reference content
    @Override
    public ReturnOption handle(FileDescriptor file, ByteBuf data) {
        if (file == FileDescriptor.FINAL)
            return this.downstream.handle(file, data);

        ByteBuf in = data;

        if (in != null) {
            while (in.isReadable()) {
                int amt = Math.min(in.readableBytes(), this.size - this.currchunk);

                ByteBuf out = in.copy(in.readerIndex(), amt);

                in.skipBytes(amt);
                this.currchunk += amt;

                boolean eof = (this.currchunk == this.size) || (!in.isReadable() && file.isEof());

                this.nextMessage(out, file, eof);

                if (eof) {
                    this.seqnum++;
                    this.currchunk = 0;
                }
            }

            in.release();
        } else if (file.isEof()) {
            this.nextMessage(null, file, false);
        }

        // write all messages in the queue
        while (this.outlist.size() > 0) {
            ReturnOption ret = this.downstream.handle(this.outlist.remove(0), this.outbuf.remove(0));

            if (ret != ReturnOption.CONTINUE)
                return ret;
        }

        return ReturnOption.CONTINUE;
    }

    public void nextMessage(ByteBuf out, FileDescriptor curr, boolean eof) {
        // create the output message
        FileDescriptor blk = new FileDescriptor();

        blk.setModTime(System.currentTimeMillis());

        // keep the path, just vary the name to the template
        blk.setPath(curr.path().resolvePeer("/" + this.template.replace("%seq%", this.seqnum + "")));

        blk.setEof(eof);

        if (eof)
            blk.setSize(this.currchunk);
        else
            blk.setSize(0); // don't know yet

        this.outlist.add(blk);
        this.outbuf.add(out);
    }

    @Override
    public void read() {
        // write all messages in the queue
        while (this.outlist.size() > 0) {
            ReturnOption ret = this.downstream.handle(this.outlist.remove(0), this.outbuf.remove(0));

            if (ret != ReturnOption.CONTINUE)
                return;
        }

        this.upstream.read();
    }
}