SiLeBAT/FSK-Lab

View on GitHub
de.bund.bfr.knime.fsklab.r/src/de/bund/bfr/knime/fsklab/r/client/IRController.java

Summary

Maintainability
B
4 hrs
Test Coverage
/***************************************************************************************************
 * Copyright (c) 2015 Federal Institute for Risk Assessment (BfR), Germany
 * <p>
 * This program 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.
 * <p>
 * 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.
 * <p>
 * You should have received a copy of the GNU General Public License along with this program. If
 * not, see <http://www.gnu.org/licenses/>.
 * <p>
 * Contributors: Department Biological Safety - BfR
 **************************************************************************************************/

package de.bund.bfr.knime.fsklab.r.client;

import java.io.File;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import org.knime.core.data.MissingCell;
import org.knime.core.node.BufferedDataTable;
import org.knime.core.node.CanceledExecutionException;
import org.knime.core.node.ExecutionContext;
import org.knime.core.node.ExecutionMonitor;
import org.knime.core.node.port.PortObject;
import org.knime.core.node.workflow.FlowVariable;
import org.knime.core.node.workflow.NodeContext;
import org.knime.core.util.ThreadUtils;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.Rserve.RConnection;

/**
 * Interface for RController.
 *
 * @author Jonathan Hale
 */
public interface IRController extends AutoCloseable {

  /**
   * Marker class for exceptions during R configuration or execution.
   * 
   * @author Jonathan Hale, KNIME, Konstanz, Germany
   */
  class RException extends Exception {
    /** Generated serialVersionUID */
    private static final long serialVersionUID = 2815440774381106769L;

    /** Message constants */
    static String MSG_EVAL_FAILED = "R evaluation failed";

    /** Constructor */
    public RException(final String msg, final Throwable cause) {
      super(msg, cause);
    }
  }

  /**
   * Marker class for exception occurring when trying to use RController when not initialized.
   */
  class RControllerNotInitializedException extends RuntimeException {
    /** Generated serialVersionUID */
    private static final long serialVersionUID = 7059728194387457225L;

    /** Constructor */
    RControllerNotInitializedException() {
      super("CODING PROBLEM\tRController was not initialized at this point.");
    }
  }

  /**
   * Initialize everything which may fail. This includes starting up servers/checking for libraries,
   * etc.
   *
   * @throws RException
   */
  void initialize() throws RException;

  /**
   * @return <code>true</code> if {@link #initialize()} was called on this instance and
   *         {@link #close()} has not been called since.
   */
  boolean isInitialized();

  /**
   * Set whether to use {@link NodeContext}s for Threads.
   *
   * @param useNodeContext Whether to use node contexts
   * @see ThreadUtils#threadWithContext(Runnable)
   * @see ThreadUtils#threadWithContext(Runnable, String)
   * @see IRController#isUsingNodeContext()
   */
  void setUseNodeContext(boolean useNodeContext);

  /**
   * @return <code>true</code> if currently using NodeContexts in threads.
   * @see IRController#setUseNodeContext(boolean)
   */
  boolean isUsingNodeContext();

  /** @return The underlying REngine (usually an {@link RConnection}) */
  RConnection getREngine();

  /**
   * Evaluate R code. This may have side effects on the workspace of the RController.
   *
   * @param expr the R expression to evaluate
   * @param cmd the R expression to evaluate
   * @param resolve Whether to resolve the resulting reference, if <code>false</code> null returned
   *        (unless exception is thrown)
   * @return result of evaluation
   * @throws RException
   */
  REXP eval(String expr, boolean resolve) throws RException;

  /**
   * Evaluate R code in a separate thread to be able to cancel it.
   *
   * @param cmd The R command
   * @param exec only used for checking if execution is cancelled
   * @param resolve Whether to resolve the resulting reference
   * @return Result of the evaluation, either a reference (if resolve is false) or the resolved
   *         value.
   * @throws RException
   * @throws CanceledExecutionException
   * @throws InterruptedException
   */
  REXP monitoredEval(String cmd, ExecutionMonitor exec, boolean resolve)
      throws RException, CanceledExecutionException, InterruptedException;

  /**
   * Assign an integer into an R variable.
   * 
   * @param symbol symbol name
   * @param value value to assign
   * @throws RException
   */
  void assign(String symbol, int value) throws RException;

  /**
   * Assign a double into an R variable.
   * 
   * @param symbol symbol name
   * @param value value to assign
   * @throws RException
   */
  void assign(String symbol, double value) throws RException;

  /**
   * Assign an REXP an R variable.
   * 
   * @param expr Expression to assign the value to. Usually a variable name
   * @param value Value to assign
   * @throws RException
   */
  void assign(String expr, String value) throws RException;

  /**
   * Assign an REXP an R variable.
   *
   * @param expr Expression to assign the value to. Usually a variable name
   * @param value Value to assign
   * @throws RException
   */
  void assign(String expr, REXP value) throws RException;

  /**
   * Assign an R variable in a separate thread to be able to cancel it.
   *
   * @param symbol R variable name
   * @param value REXP value to assign to the variable
   * @param exec Execution Monitor
   * @throws RException
   * @throws CanceledExecutionException
   * @throws InterruptedException
   * @see #monitoredEval(String, ExecutionMonitor, boolean)
   * @see #assign(String, REXP)
   */
  void monitoredAssign(String symbol, REXP value, ExecutionMonitor exec)
      throws RException, CanceledExecutionException, InterruptedException;

  /**
   * Clear the R workspace (remove all variables and imported packages).
   *
   * @param exec Execution Monitor
   * @throws RException
   * @throws CanceledExecutionException
   */
  void clearWorkspace(ExecutionMonitor exec) throws RException, CanceledExecutionException;

  /**
   * @param workspaceFile R workspace file to read
   * @param tempWorkspaceFile the workspace file
   * @param exec execution monitor to report progress on
   * @return List of libraries which were previously imported in the workspace. See
   *         {@link #importListOfLibrariesAndDelete()}.
   * @throws RException
   * @throws CanceledExecutionException
   */
  List<String> clearAndReadWorkspace(final File workspaceFile, final ExecutionMonitor exec)
      throws RException, CanceledExecutionException;

  /**
   * Write R variables into a R variable in the current workspace
   *
   * @param inFlowVariables Flow variables to export into the R workspace
   * @param name Name for the R variable to contain the flow variables
   * @param exec Execution monitor
   * @throws RException
   * @throws CanceledExecutionException
   */
  void exportFlowVariables(Collection<FlowVariable> inFlowVariables, String name,
      ExecutionMonitor exec) throws RException, CanceledExecutionException;

  /**
   * Get flow variables from a R variable.
   *
   * @param variableName Name of the variable to get the {@link FlowVariable}s from.
   * @return The extracted flow variables.
   * @throws RException If an R related error occurred during execution.
   */
  Collection<FlowVariable> importFlowVariables(String variableName) throws RException;

  /**
   * Assign a {@link BufferedDataTable} to a R variable in the current workspace.
   *
   * @param symbol R variable to assign to.
   * @param value The table to assign to the variable.
   * @param exec For monitoring the progress.
   * @param batchSize max number of rows to send to R per batch.
   * @param type R type for "symbol" to provide the table data as
   * @param sendRowNames Whether to send names of rows to R with the input table
   * @throws RException If an R related error occurred during execution.
   * @throws CanceledExecutionException If execution was cancelled.
   * @throws InterruptedException If a thread was interrupted.
   */
  void monitoredAssign(String symbol, BufferedDataTable value, ExecutionMonitor exec, int batchSize,
      String type, boolean sendRowNames)
      throws RException, CanceledExecutionException, InterruptedException;

  /**
   * Import a BufferedDataTable from the R expression <code>string</code>.
   *
   * @param string R expression (variable for e.g.) to retrieve a data.frame which is then converted
   *        into a BufferedDataTable.
   * @param nonNumbersAsMissing Convert NaN and Infinity to {@link MissingCell}.
   * @param exec Execution context for creating the table and monitoring execution.
   * @return The created BufferedDataTable.
   * @throws RException
   * @throws CanceledExecutionException
   */
  BufferedDataTable importBufferedDataTable(String string, boolean nonNumbersAsMissing,
      ExecutionContext exec) throws RException, CanceledExecutionException;

  /**
   * Get list of libraries imported in the current session and then delete those imports.
   *
   * @return The list of deleted imports
   * @throws RException
   */
  List<String> importListOfLibrariesAndDelete() throws RException;

  /**
   * Save the workspace in the current R session to the specified file.
   *
   * @param workspaceFile File to save the workspace to.
   * @param exec For monitoring the progress.
   * @throws RException If an R related error occurred during execution.
   * @throws CanceledExecutionException If execution was cancelled.
   */
  void saveWorkspace(Path workspace, ExecutionMonitor exec)
      throws RException, CanceledExecutionException;

  /**
   * Import RInputPorts and BufferedDataTables into the current R workspace.
   *
   * @param inData ports to import
   * @param exec For monitoring the progess.
   * @param batchSize max number of rows to send to R per batch.
   * @param rType R type for "symbol" to provide the table data as
   * @param sendRowNames Whether to send row names of input tables to R
   * @throws RException
   * @throws CanceledExecutionException
   */
  void importDataFromPorts(PortObject[] inData, ExecutionMonitor exec, final int batchSize,
      final String rType, final boolean sendRowNames) throws RException, CanceledExecutionException;

  /**
   * Returns {@link Path} representing the current working directory of the R process.
   * 
   * @see <a href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/getwd.html">getwd</a>
   * @throws RMismatchException if the working directory is not available
   */
  Path getWorkingDirectory() throws RException, REXPMismatchException;

  /** Sets the current working directory of the R process. */
  void setWorkingDirectory(final Path workingDirectory) throws RException;

  /**
   * Add a library tree to look for packages.
   * 
   * @see <a href=
   *      "https://stat.ethz.ch/R-manual/R-devel/library/base/html/libPaths.html">.libPaths</a>
   */
  void addPackagePath(final Path path) throws RException;

  /**
   * Restore library trees to the default library.
   * 
   * @throws REXPMismatchException
   */
  void restorePackagePath() throws RException, REXPMismatchException;
}