de.helmholtz_muenchen.ibis.utils.abstractNodes.RNode.RNodeModel.java Source code

Java tutorial

Introduction

Here is the source code for de.helmholtz_muenchen.ibis.utils.abstractNodes.RNode.RNodeModel.java

Source

/**
 *  Copyright (C) 2016 the Knime4NGS contributors.
 *  Website: http://ibisngs.github.io/knime4ngs
 *  
 *  This file is part of the KNIME4NGS KNIME extension.
 *  
 *  The KNIME4NGS extension is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *  
 *  This program 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 General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.helmholtz_muenchen.ibis.utils.abstractNodes.RNode;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import org.apache.commons.lang3.StringUtils;
import org.knime.core.node.BufferedDataTable;
import org.knime.core.node.ExecutionContext;
import org.knime.core.node.NodeLogger;
import org.knime.core.node.defaultnodesettings.SettingsModelColumnName;
import org.knime.core.node.port.PortType;

import de.helmholtz_muenchen.ibis.utils.IO;
import de.helmholtz_muenchen.ibis.utils.SuccessfulRunChecker;
import de.helmholtz_muenchen.ibis.utils.abstractNodes.ScriptNode.ScriptNodeModel;
import de.helmholtz_muenchen.ibis.utils.threads.UnsuccessfulExecutionException;

public abstract class RNodeModel extends ScriptNodeModel {
    public static final String ROW_ID = "ROWID"; // column name used for rowID

    public static final String R_SCRIPTS_PATH = "R";
    public static final String GLOBALS_R = IO.getScriptPath() + ScriptNodeModel.SCRIPTS_SUBFOLDER
            + File.separatorChar + R_SCRIPTS_PATH + File.separatorChar + "utils" + File.separatorChar + "GLOBALS.R";

    private final HashMap<String, String> ARGUMENTS = new HashMap<String, String>();;
    protected final String[] INPUT_FILE_ARGUMENTS;
    protected final String[] OUTPUT_FILE_ARGUMENTS;

    private static final NodeLogger LOGGER = NodeLogger.getLogger(RNodeModel.class);

    protected RNodeModel(int nrInDataPorts, int nrOutDataPorts, String script, String[] input_file_arguments,
            String[] output_file_arguments) {
        super(nrInDataPorts, nrOutDataPorts, script);

        // check number of file names
        if (input_file_arguments.length != this.getNrInPorts()) {
            LOGGER.error("HAVING " + this.getNrInPorts() + " INPUT FILES BUT " + input_file_arguments.length
                    + " NAMES!");
        }
        if (output_file_arguments.length != this.getNrOutPorts()) {
            LOGGER.error("HAVING " + this.getNrOutPorts() + " OUTPUT FILES BUT " + output_file_arguments.length
                    + " NAMES!");
        }
        this.INPUT_FILE_ARGUMENTS = input_file_arguments;
        this.OUTPUT_FILE_ARGUMENTS = output_file_arguments;
    }

    protected RNodeModel(final PortType[] inPortTypes, final PortType[] outPortTypes, String script,
            String[] input_file_arguments, String[] output_file_arguments) {
        super(inPortTypes, outPortTypes, script);
        // TODO what if PortTypes are not tables to write???

        // check number of file names
        if (input_file_arguments.length > inPortTypes.length) {
            LOGGER.error("HAVING " + this.getNrInPorts() + " INPUT FILES BUT " + input_file_arguments.length
                    + " NAMES!");
        }
        if (output_file_arguments.length > outPortTypes.length) {
            LOGGER.error("HAVING " + this.getNrOutPorts() + " OUTPUT FILES BUT " + output_file_arguments.length
                    + " NAMES!");
        }
        this.INPUT_FILE_ARGUMENTS = input_file_arguments;
        this.OUTPUT_FILE_ARGUMENTS = output_file_arguments;
    }

    @Override
    protected String getScriptPath() {
        return (super.getScriptPath() + R_SCRIPTS_PATH + File.separatorChar);
    }

    protected String getRscriptBinary() {
        if (this.getAvailableFlowVariables().containsKey("Rscript")) {
            return (this.getAvailableFlowVariables().get("Rscript").getStringValue());
        }
        return ("Rscript");
    }

    protected void prepareInputData(final BufferedDataTable[] inData, final ExecutionContext exec)
            throws Exception {

        //////////////////////////////////////////////////////////////////////////
        // PREPARE INPUT FILES
        //////////////////////////////////////////////////////////////////////////
        //      exec.setProgress(0.00);
        //      exec.setProgress("writing input data");
        for (int i = 0; i < INPUT_FILE_ARGUMENTS.length; i++) {
            exec.checkCanceled();
            if (inData[i] != null) {
                File tmpFile = null;
                try {
                    tmpFile = File.createTempFile(
                            "knime_R_connector_" + this.SCRIPT.replaceAll(File.separatorChar + "", "_") + "_input_",
                            ".csv");
                    this.addArgument(this.INPUT_FILE_ARGUMENTS[i], tmpFile.getCanonicalPath());
                } catch (IOException e) {
                    LOGGER.error("unable to create temp file!");
                    throw (e);
                }
                IO.writeAsCSV(inData[i], tmpFile, exec, LOGGER);
            } else {
                this.removeArgument(this.INPUT_FILE_ARGUMENTS[i]);
            }
            exec.checkCanceled();
        }
    }

    protected String[] prepareOutputData(final BufferedDataTable[] inData, final ExecutionContext exec)
            throws Exception {
        //      exec.setProgress(0.05);
        //      exec.setProgress("preparing output data");
        String[] outFiles = new String[OUTPUT_FILE_ARGUMENTS.length];
        for (int i = 0; i < OUTPUT_FILE_ARGUMENTS.length; i++) {
            exec.checkCanceled();
            File tmpFile = null;
            try {
                tmpFile = File.createTempFile(
                        "knime_R_connector_" + this.SCRIPT.replaceAll(File.separatorChar + "", "_") + "_output_",
                        ".csv");
                this.addArgument(this.OUTPUT_FILE_ARGUMENTS[i], tmpFile.getCanonicalPath());
                outFiles[i] = tmpFile.getCanonicalPath();
            } catch (IOException e) {
                LOGGER.error("unable to create temp file!");
                throw (e);
            }
        }
        return (outFiles);
    }

    @Override
    protected BufferedDataTable[] execute(final BufferedDataTable[] inData, final ExecutionContext exec)
            throws Exception {
        //////////////////////////////////////////////////////////////////////////
        // PREPARE INPUT DATA
        //////////////////////////////////////////////////////////////////////////
        prepareInputData(inData, exec);

        //////////////////////////////////////////////////////////////////////////
        // PREPARE OUTPUT FILES
        //////////////////////////////////////////////////////////////////////////
        String[] outFiles = prepareOutputData(inData, exec);

        //////////////////////////////////////////////////////////////////////////
        // RUN COMMAND
        //////////////////////////////////////////////////////////////////////////
        //      exec.setProgress(0.10);
        //      exec.setProgress("executing script");
        LOGGER.info("Running Rscript with arguments: " + getArgumentsAsVector());
        try {
            File tmpFile = File.createTempFile(
                    "knime_R_connector_" + this.SCRIPT.replaceAll(File.separatorChar + "", "_"),
                    SuccessfulRunChecker.LOCK_ENDING);
            super.executeScript(exec, null, tmpFile);
        } catch (UnsuccessfulExecutionException e) {
            throw new UnsuccessfulExecutionException("R command failed\nSTDOUT:" + IO.tail(this.getHTEOUT(), 5)
                    + "\nSTDERR:" + IO.tail(this.getHTEERR(), 5));
        }

        //////////////////////////////////////////////////////////////////////////
        // READ DATA
        //////////////////////////////////////////////////////////////////////////
        //      exec.setProgress(0.90);
        //      exec.setProgress("reading output");
        BufferedDataTable[] output = IO.readCSV(exec, outFiles, RNodeModel.LOGGER, true, true);
        //      exec.setProgress(1.0);

        return (output);
    }

    public static String tail(String string) {
        int i = string.lastIndexOf("\n");
        return (string.substring(i));
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////
    /// OVERIDE KNIME NODE METHODS
    /////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * {@inheritDoc}
     */
    @Override
    protected void reset() {
        super.reset();
        this.ARGUMENTS.clear();
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////
    /// COMMANDLINE ARGUMENTS
    /////////////////////////////////////////////////////////////////////////////////////////////////
    public void addArgument(String arg, String value) {
        this.ARGUMENTS.put(arg, value);
    }

    @SuppressWarnings("rawtypes")
    public void addArgument(String arg, Collection value) {
        this.addArgument(arg, StringUtils.join(value, ','));
    }

    public void addArgument(String arg, int value) {
        this.addArgument(arg, String.valueOf(value));
    }

    public void addArgument(String arg, double value) {
        this.addArgument(arg, String.valueOf(value));
    }

    public void addArgument(String arg, float value) {
        this.addArgument(arg, String.valueOf(value));
    }

    public void addArgument(String arg, SettingsModelColumnName value) {
        if (value.getColumnName() == null) {
            if (value.useRowID()) {
                this.addArgument(arg, RNodeModel.ROW_ID);
            }
        } else {
            this.addArgument(arg, value.getColumnName());
        }
    }

    public void removeArgument(String arg) {
        this.ARGUMENTS.remove(arg);
    }

    public void addFlag(String arg) {
        this.ARGUMENTS.put(arg, null);
    }

    public void removeFlag(String arg) {
        this.removeArgument(arg);
    }

    public void setFlag(String arg, boolean b) {
        if (b) {
            this.addFlag(arg);
        } else {
            this.removeFlag(arg);
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////
    /// GETTERS
    /////////////////////////////////////////////////////////////////////////////////////////////////
    public String getArguments() {
        StringBuilder args = new StringBuilder(" --globals \"" + GLOBALS_R + "\"");
        for (String key : this.ARGUMENTS.keySet()) {
            // key
            args.append(" " + key);

            // value
            if (this.ARGUMENTS.get(key) != null) {
                args.append(" \"" + this.ARGUMENTS.get(key) + "\"");
            }
        }
        return (args.toString());
    }

    @Override
    protected String[] getCommand() {
        ArrayList<String> command = new ArrayList<String>();
        command.add(this.getRscriptBinary());
        command.add(this.SCRIPT);
        command.add("--globals");
        command.add(GLOBALS_R);
        for (String key : this.ARGUMENTS.keySet()) {
            command.add(key);
            // value
            if (this.ARGUMENTS.get(key) != null) {
                command.add(this.ARGUMENTS.get(key));
            }
        }

        return (command.toArray(new String[command.size()]));
    }

    public String getOutfile() {
        return null;
    }

    public String getArgumentsAsVector() {
        StringBuilder args = new StringBuilder("args.in <- c( \"--globals\", \"" + GLOBALS_R + "\"");
        for (String key : this.ARGUMENTS.keySet()) {
            // key
            args.append(", \"" + key + "\"");

            // value
            if (this.ARGUMENTS.get(key) != null) {
                args.append(", \"" + this.ARGUMENTS.get(key) + "\"");
            }
        }
        args.append(")");
        return (args.toString());
    }

}