package com.pivotalservices.java2r; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.Scanner; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.rosuda.REngine.REXP; import org.rosuda.REngine.REXPMismatchException; import org.rosuda.REngine.REngine; import org.rosuda.REngine.REngineException; import org.rosuda.REngine.JRI.JRIEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * Synchronized access to native R engine * * To use: 1. Install R and rJava using sudo calc/lib/install-R.sh * 2. Set environment variable R_HOME=/usr/lib/R * * @author G. Miceli */ @Component public class R { private static final String[] R_PARAMS = { "--vanilla", "--slave" }; private REngine engine; private final Logger logger; private RStdOutputListner rStdOutputListner; public R() { logger = LoggerFactory.getLogger(getClass()); } @PostConstruct synchronized public void startup() { try { String jriPath = getJriPath(); System.out.println("JRI PATH: " + jriPath); if (jriPath != null) { SystemUtils.addLibraryPath(jriPath); logger.info("JRI path added to library path: " + jriPath); } rStdOutputListner = new RStdOutputListner(this); engine = REngine.engineForClass(JRIEngine.class.getName(), R_PARAMS, rStdOutputListner, true); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Returns JRI absolute path from R. * JRI is included by rJava, the usual path should be /usr/lib/R/library/rJava/jri */ private String getJriPath() { Scanner s = null; System.out.println("Getting JRI path"); try { ProcessBuilder pb = new ProcessBuilder("R", "--slave", "-e", "system.file('jri',package='rJava')"); Process p = pb.start(); p.waitFor(); InputStream inputStream = p.getInputStream(); s = new Scanner(inputStream); s.next("\\[1\\]"); String path = s.next(".*"); // Remove quotes path = path.substring(1, path.length() - 1); return path; } catch (Exception e) { logger.warn("Error getting JRI library path from R"); // throw new // RuntimeException("Error getting JRI library path from R"); return null; } finally { if ( s != null ) { s.close(); } } } @PreDestroy synchronized public void shutdown() { engine.close(); } public REnvironment newEnvironment() throws RException { try { REXP env = engine.newEnvironment(null, false); return new REnvironment(this, env); } catch (REXPMismatchException e) { throw new RException(e); } catch (REngineException e) { throw new RException(e); } } synchronized REXP eval(String expr, REXP env, boolean resolve, RLogger logger) throws RException { try { // before execution register logger rStdOutputListner.registerLogger(logger); REXP rexp = engine.parseAndEval(expr, env, resolve); return rexp; } catch (REXPMismatchException e) { throw new RException(e); } catch (REngineException e) { throw new RException(e); } finally { // after execution unregister logger rStdOutputListner.unregisterLogger(logger); } } synchronized void assign(String symbol, REXP value, REXP env) throws RException { try { engine.assign(symbol, value, env); } catch (REXPMismatchException e) { throw new RException(e); } catch (REngineException e) { throw new RException(e); } } Logger getLogger() { return logger; } }