divconq.ctp.stream.FileDestStream.java Source code

Java tutorial

Introduction

Here is the source code for divconq.ctp.stream.FileDestStream.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.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

import divconq.ctp.f.FileDescriptor;
import divconq.filestore.IFileStoreDriver;
import divconq.filestore.IFileStoreFile;
import divconq.filestore.local.FileSystemFile;
import divconq.lang.op.OperationContext;
import divconq.script.StackEntry;
import divconq.struct.Struct;
import divconq.struct.scalar.NullStruct;
import divconq.xml.XElement;

public class FileDestStream extends BaseStream implements IStreamDest {
    protected FileSystemFile file = null;
    protected FileChannel out = null;
    protected boolean userelpath = false;
    protected String relpath = "";

    public FileDestStream(FileSystemFile file) {
        this.file = file;
    }

    public FileDestStream withRelative(boolean v) {
        this.userelpath = v;
        return this;
    }

    // for use with dcScript
    @Override
    public void init(StackEntry stack, XElement el, boolean autorelative) {
        if (autorelative || stack.boolFromElement(el, "Relative", false) || el.getName().startsWith("X")) {
            this.userelpath = true;
        }

        Struct src = stack.refFromElement(el, "RelativeTo");

        if ((src != null) && !(src instanceof NullStruct)) {
            if (src instanceof IFileStoreDriver)
                this.relpath = "";
            else if (src instanceof IFileStoreFile)
                this.relpath = ((IFileStoreFile) src).getPath();
            else
                this.relpath = src.toString();

            this.userelpath = true;
        }
    }

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

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

        this.out = null;
        this.file = null;

        super.close();
    }

    @Override
    public ReturnOption handle(FileDescriptor file, ByteBuf data) {
        if (file == FileDescriptor.FINAL) {
            OperationContext.get().getTaskRun().complete();
            return ReturnOption.DONE;
        }

        if (this.file.isFolder())
            return this.handleLocalFolder(file, data);

        return this.handleLocalFile(file, data);
    }

    public ReturnOption handleLocalFile(FileDescriptor file, ByteBuf data) {
        if (file.isFolder()) {
            if (data != null)
                data.release();

            OperationContext.get().getTaskRun().kill("Folder cannot be stored into a file");
            return ReturnOption.DONE;
        }

        if (data != null) {
            if (this.out == null) {
                try {
                    Path dpath = this.file.localPath();

                    Files.createDirectories(dpath.getParent());

                    this.out = FileChannel.open(dpath, StandardOpenOption.CREATE, StandardOpenOption.WRITE,
                            StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC);
                } catch (IOException x) {
                    if (data != null)
                        data.release();

                    OperationContext.get().getTaskRun().kill("Problem opening destination file: " + x);
                    return ReturnOption.DONE;
                }
            }

            for (ByteBuffer buff : data.nioBuffers()) {
                try {
                    this.out.write(buff);
                } catch (IOException x) {
                    data.release();
                    OperationContext.get().getTaskRun().kill("Problem writing destination file: " + x);
                    return ReturnOption.DONE;
                }
            }

            data.release();
        }

        if (file.isEof()) {
            try {
                if (this.out != null) {
                    this.out.close();
                    this.out = null;
                }

                this.file.refreshProps();
            } catch (IOException x) {
                OperationContext.get().getTaskRun().kill("Problem closing destination file: " + x);
                return ReturnOption.DONE;
            }
        }

        return ReturnOption.CONTINUE;
    }

    public ReturnOption handleLocalFolder(FileDescriptor file, ByteBuf data) {
        Path folder = this.file.localPath();

        if (Files.notExists(folder))
            try {
                Files.createDirectories(folder);
            } catch (IOException x) {
                if (data != null)
                    data.release();

                OperationContext.get().getTaskRun().kill("Problem making destination top folder: " + x);
                return ReturnOption.DONE;
            }

        String fpath = (this.userelpath) ? this.relpath + file.getPath() : "/" + file.path().getFileName();

        if (file.isFolder()) {
            try {
                Files.createDirectories(folder.resolve(fpath.substring(1)));
            } catch (IOException x) {
                if (data != null)
                    data.release();

                OperationContext.get().getTaskRun().kill("Problem making destination folder: " + x);
                return ReturnOption.DONE;
            }

            return ReturnOption.CONTINUE;
        }

        if (this.out == null)
            try {
                Path dpath = folder.resolve(fpath.substring(1));

                Files.createDirectories(dpath.getParent());

                this.out = FileChannel.open(dpath, StandardOpenOption.CREATE, StandardOpenOption.WRITE,
                        StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.SYNC);
            } catch (IOException x) {
                if (data != null)
                    data.release();

                OperationContext.get().getTaskRun().kill("Problem opening destination file: " + x);
                return ReturnOption.DONE;
            }

        if (data != null) {
            for (ByteBuffer buff : data.nioBuffers()) {
                try {
                    this.out.write(buff);
                } catch (IOException x) {
                    data.release();
                    OperationContext.get().getTaskRun().kill("Problem writing destination file: " + x);
                    return ReturnOption.DONE;
                }
            }

            data.release();
        }

        if (file.isEof()) {
            try {
                this.out.close();
                this.out = null;

                this.file.refreshProps();
            } catch (IOException x) {
                OperationContext.get().getTaskRun().kill("Problem closing destination file: " + x);
                return ReturnOption.DONE;
            }
        }

        return ReturnOption.CONTINUE;
    }

    @Override
    public void read() {
        // we are terminal, no downstream should call us
        OperationContext.get().getTaskRun().kill("File destination cannot be a source");
    }

    @Override
    public void execute() {
        // TODO optimize if upstream is local file also

        this.upstream.read();
    }
}