divconq.ctp.stream.FileSourceStream.java Source code

Java tutorial

Introduction

Here is the source code for divconq.ctp.stream.FileSourceStream.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 io.netty.buffer.ByteBuf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;

import divconq.ctp.f.FileDescriptor;
import divconq.filestore.IFileCollection;
import divconq.filestore.IFileStoreFile;
import divconq.filestore.local.FileSystemFile;
import divconq.hub.Hub;
import divconq.lang.op.FuncCallback;
import divconq.lang.op.OperationContext;
import divconq.script.StackEntry;
import divconq.xml.XElement;

public class FileSourceStream extends BaseStream implements IStreamSource {
    protected IFileCollection source = null;
    protected IFileStoreFile current = null;
    protected FileChannel in = null;
    protected long insize = 0;
    protected long inprog = 0;

    public FileSourceStream(IFileCollection src) {
        this.source = src;
    }

    // for use with dcScript
    @Override
    public void init(StackEntry stack, XElement el) {
        // anything we need to gleam from the xml?
    }

    @Override
    public ReturnOption handle(FileDescriptor file, ByteBuf data) {
        // we are at top of stream, nothing to do here
        return ReturnOption.CONTINUE;
    }

    @Override
    public void close() {
        //System.out.println("File SRC killed");   // TODO

        if (this.in != null)
            try {
                this.in.close();
            } catch (IOException x) {
            }

        this.in = null;
        this.current = null;
        this.source = null;

        super.close();
    }

    /**
     * Someone downstream wants more data
     */
    @Override
    public void read() {
        if (this.source == null) {
            this.downstream.handle(FileDescriptor.FINAL, null);
            return;
        }

        if (this.current == null) {
            this.source.next(new FuncCallback<IFileStoreFile>() {
                @Override
                public void callback() {
                    if (this.hasErrors()) {
                        OperationContext.get().getTaskRun().kill();
                        return;
                    }

                    FileSourceStream.this.readFile(this.getResult());
                }
            });
        }
        // folders are handled in 1 msg, so we wouldn't get here in second or later call to a file
        else if (this.current instanceof FileSystemFile)
            FileSourceStream.this.readLocalFile();
        else {
            FileSourceStream.this.readOtherFile();
        }
    }

    public void readFile(IFileStoreFile file) {
        this.current = file;

        // if we reached the end of the collection then finish
        if (this.current == null) {
            this.downstream.handle(FileDescriptor.FINAL, null);
        } else if (this.current.isFolder()) {
            FileDescriptor fref = FileDescriptor.fromFileStore(this.current);
            fref.setIsFolder(true);
            fref.setPath(this.current.path().subpath(this.source.path()));

            if (this.downstream.handle(fref, null) == ReturnOption.CONTINUE) {
                FileSourceStream.this.current = null;
                OperationContext.get().getTaskRun().resume();
            }
        } else if (this.current instanceof FileSystemFile)
            FileSourceStream.this.readLocalFile();
        else {
            FileSourceStream.this.readOtherFile();
        }
    }

    public void readOtherFile() {
        // TODO abstract out so this class is a FileCollectionSourceStream and we
        // use it pull out the source streams of files, which we then use as if upstream from us
    }

    // release data if error
    public void readLocalFile() {
        FileSystemFile fs = (FileSystemFile) this.current;

        if (this.in == null) {
            this.insize = fs.getSize();

            // As a source we are responsible for progress tracking
            OperationContext.get().setAmountCompleted(0);

            try {
                this.in = FileChannel.open(fs.localPath(), StandardOpenOption.READ);
            } catch (IOException x) {
                OperationContext.get().getTaskRun().kill("Unable to read source file " + x);
                return;
            }
        }

        while (true) {
            // TODO sizing?
            ByteBuf data = Hub.instance.getBufferAllocator().heapBuffer(32768);

            ByteBuffer buffer = ByteBuffer.wrap(data.array(), data.arrayOffset(), data.capacity());

            int pos = -1;

            try {
                pos = (int) this.in.read(buffer);
            } catch (IOException x1) {
                OperationContext.get().getTaskRun().kill("Problem reading source file: " + x1);
                data.release();
                return;
            }

            FileDescriptor fref = FileDescriptor.fromFileStore(this.current);
            fref.setPath(this.current.path().subpath(this.source.path()));

            System.out.println("writing: " + fref.getPath() + " from: " + this.inprog);

            if (pos == -1) {
                try {
                    this.in.close();
                } catch (IOException x) {
                    OperationContext.get().getTaskRun().kill("Problem closing source file: " + x);
                    data.release();
                    return;
                }

                OperationContext.get().setAmountCompleted(100);

                fref.setEof(true);

                this.current = null;
                this.in = null;
                this.insize = 0;
                this.inprog = 0;
            } else {
                this.inprog += pos;

                data.writerIndex(pos);
                OperationContext.get().setAmountCompleted((int) (this.inprog * 100 / this.insize));
            }

            if (this.downstream.handle(fref, data) != ReturnOption.CONTINUE)
                break;

            if (this.current == null) {
                // we need the next file
                OperationContext.get().getTaskRun().resume();

                // wait on the implied request
                break;
            }
        }
    }
}