Abhijay Ghildyal Abhijay Ghildyal - 1 month ago 16
R Question

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)

Answer

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.