Search code examples
javarrserve

Identifying string values or error sent from RServe in java


This is my sample R file :

# filename: sample.R
main <- function (){
  returnStringValue <- "ignore"
  return (returnStringValue)
}
main()

Now I am trying to source on the file on Rserve using java:

import org.rosuda.REngine.REXP;
import org.rosuda.REngine.Rserve.RConnection;

public class RServeTest {

    static RConnection rcon;

    public static void main(String[] args) {
        try {

            String fileName = "sample.R";
            String filePath = "/filepath/";

            try {
                rcon = new RConnection();
            }
            catch(Exception e){
                System.out.println("Error Connecting: "+e);
            }

            String rCode = "source(\""+filePath+fileName+"\")";
            System.out.println("Rscript call on file: "+rCode);


            REXP r = rcon.parseAndEval("try(eval(parse(text="+rCode+")),silent=TRUE)");

            System.out.println("r object: "+r.asString());

            if (r.inherits("try-error")) 
                System.err.println("Error: "+r.asString());
            else 
                System.out.println("Executed R code successfully.");


        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

which gives me the following error:

Rscript call on file: source("/home/maverick/Documents/sem3/agent code/sample.R")
Error: Error in eval(expr, envir, enclos) : object 'ignore' not found

How do I handle string values getting returned from the R code, without affecting the errors getting caught?

For eg:

Let's say I have a bug in my code:

main <- function (){
  returnStringValue <- "ignore"

  # error
  var1+1

  return (returnStringValue)
}
main()

The java code should log :

Rscript call on file: source("/filepath/sample.R")
Error: Error in main() : object 'var1' not found

rather than logging :

org.rosuda.REngine.Rserve.RserveException: eval failed, request status: error code: 127
    at org.rosuda.REngine.Rserve.RConnection.eval(RConnection.java:233)
    at RServeTest.main(RServeTest.java:39)

Solution

  • The error can be solved by returning a json object from R, instead of a string value. Here is how I solved this error:

    Java code to source R file and run main() function:

    import org.rosuda.REngine.REXP;
    import org.rosuda.REngine.Rserve.RConnection;
    
    public class RServeTest {
    
        static RConnection rcon;
    
        public static void main(String[] args) {
            try {
    
                String fileName = "sample.R";
                // Note: Change filename for testing different samples
    
                String filePath = "/filepath/";
    
                try {
                    rcon = new RConnection();
                }
                catch(Exception e){
                    System.out.println("Error Connecting: "+e);
                }
    
                String rCode = "source(\""+filePath+fileName+"\")";
                System.out.println("Rscript call on file: "+rCode);
    
                // Source file
                REXP r0 = rcon.parseAndEval("try(eval(parse(text="+rCode+")),silent=TRUE)");
    
                // Run main() function
                REXP r = rcon.parseAndEval("try(eval(parse(text=main())),silent=TRUE)");
    
    
                System.out.println("\n---------  with try error ------------");
    
                if (r.inherits("try-error")) 
                    System.out.println("Error: "+r.asString());
                else 
                    System.out.println("Executed R code successfully."+"r object: "+r.asString());
    
                System.out.println("\n---------  without try error ------------");
    
                System.out.println("R output :"+rcon.eval("main()").asString());
    
    
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    }
    

    R code Sample 1:

    main <- function (){
      returnStringValue <- "ignore"
      return (returnStringValue)
    }
    

    Results:

    Rscript call on file: source("/filepath/sample1.R")
    
    ---------  with try error ------------
    Error: Error in eval(expr, envir, enclos) : object 'ignore' not found
    
    
    ---------  without try error ------------
    R output :ignore
    

    Without try-error method gives us the return string value we wanted, but if there is an error, as in the case below, it returns eval failed which can only be logged using the try-error method (please see sample 2).


    R code Sample 2:

    main <- function (){
    
      # error
      var1+1
    
      returnStringValue <- "ignore"
      return (returnStringValue)
    }
    

    Results:

    Rscript call on file: source("/filepath/sample2.R")
    
    ---------  with try error ------------
    Error: Error in main() : object 'var1' not found
    
    
    ---------  without try error ------------
    org.rosuda.REngine.Rserve.RserveException: eval failed, request status: error code: 127
        at org.rosuda.REngine.Rserve.RConnection.eval(RConnection.java:233)
        at RServeTest.main(RServeTest.java:43)
    

    The aforementioned issue can be dealt with, by returning a json object from R instead of a string value. Here are sample codes and results:

    R code Sample 3:

    require('rjson')
    main <- function (){
    
      # error
      var1+1
    
      returnStringValue <- "ignore"
      returnJsonObject <- toJSON(returnStringValue)
      return (returnJsonObject)
    }
    

    Results:

    Rscript call on file: source("/filepath/sample3.R")
    
    ---------  with try error ------------
    Error: Error in main() : object 'var1' not found
    
    
    ---------  without try error ------------
    org.rosuda.REngine.Rserve.RserveException: eval failed, request status: error code: 127
        at org.rosuda.REngine.Rserve.RConnection.eval(RConnection.java:233)
        at RServeTest.main(RServeTest.java:43)
    

    R code Sample 4:

    require('rjson')
    main <- function (){
    
      returnStringValue <- "ignore"
      returnJsonObject <- toJSON(returnStringValue)
    
      return (returnJsonObject)
    }
    

    Results:

    Rscript call on file: source("/filepath/sample4.R")
    
    ---------  with try error ------------
    Executed R code successfully.r object: ignore
    
    ---------  without try error ------------
    R output :"ignore"
    

    Hence, from sample 3 and 4 you can see that we have achieved our desired output.