Search code examples
javartomcatservletsrenjin

run R code from Java Servlet


I am trying to run some R code from a Java Servlet running in Eclipse as IDE on TomCat 7.0.

The END goal is to create a website running on TOMCAT or JETTY to show Graphs + Data made with existing R code that the R function returns as Base 64 code combined with the results of some existing Java and Python functions handling and creating advanced Excel files for instance.

(I am not going to use R Shiny Server for a lot of reasons so i want to run R / Python from Java)

To get a basic setup i created a Dynamic Web project with a simple servlet and a test.java file that can run R code.

test.java:

public class test {
      public static void main(String[] args) throws Exception {
          System.out.println(DoR.collectR());
      }
}

DoR.java:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class DoR {

  public static Object collectR() {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("Renjin");
    if(engine == null) {
        throw new RuntimeException("Renjin Script Engine not found on the classpath.");
    }
    Object catchR = "XX";
    try {
        catchR = engine.eval("df <- data.frame(x=1:10, y=(1:10)+rnorm(n=10));"
                + "print(df);"
                + "print(lm(y ~ x, df))");
    } catch (ScriptException e) {
        e.printStackTrace();
    }
    return catchR;
   }
}

StartTestServlet.java:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/StartTestServlet")
public class StartTestServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  public StartTestServlet() {
    super();
  }

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //response.getWriter().append("Served at: ").append(request.getContextPath()).append((CharSequence) DoR.collectR());
    response.getWriter().append("Served at: ").append(request.getContextPath());
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
  }
}

I have the libraries installed:

renjin-script-engine-0.7.0-RC2.jar
renjin-studio-0.8.1915-jar-with-dependencies.jar
slf4j-api-1.7.19.jar
slf4j-simple-1.7.19.jar

If i run the test.java as a Java Application it works fine.

If i run the servlet on the TomCat 7.0 server it works fine (without the .append((CharSequence) DoR.collectR()) )

If i run the code with .append((CharSequence) DoR.collectR()) I get the exception:

java.lang.RuntimeException: Renjin Script Engine not found on the classpath.
    ......DoR.collectR(DoR.java:16)
    ......StartTestServlet.doGet(StartTestServlet.java:19)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)

DoR.java:16 is the line with:

try {

StartTestServlet.doGet(StartTestServlet.java:19) is the line with:

response.getWriter().append("Served at: ").append(request.getContextPath()).append((CharSequence) DoR.collectR());

I have been trying all kinds of things to get this working in Eclipse Version: Mars.1 Release (4.5.1) And downloaded the Example files from Renjin / searching internet and so on but with no luck uptill now to get the R code running from within the Servlet.

Am i overlooking something simple or do i need to do it completely different ?


Solution

  • See the (newly added) eclipse-dynamic-web-project in Renjin Examples. To summarize the README:

    1. Download the standalone renjin-script-engine-0.8.1931-jar-with-dependencies.jar from the Renjin Downloads Page. You seem to be combining an old version of renjin-script-engine with the GUI jar.
    2. Copy this JAR to WebContent/WEB-INF/lib so that it will be deployed along with your application.

    Also look at your "DoR" method: you are calling print() which sends its output to standard output and returns NULL. On a webserver, this may get sent to the logs, but certainly will not end up in the response to the client.

    If you want to send the results of the lm() function to the client, you can serialize it using rjson::toJSON(), for example.