package de.hpi.i2b2.girix; import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rosuda.REngine.Rserve.RConnection; /** * simple class that start Rserve locally if it's not running already - see * mainly <code>checkLocalRserve</code> method. It spits out quite some * debugging outout of the console, so feel free to modify it for your * application if desired.<p> * <i>Important:</i> All applications should shutdown every Rserve that they * started! Never leave Rserve running if you started it after your application * quits since it may pose a security risk. Inform the user if you started an * Rserve instance. */ public class RserveSpawner { private static Log log = LogFactory.getLog(RserveSpawner.class); /** * shortcut to * <code>launchRserve(cmd, "--no-save --slave", "--no-save --slave", false, port)</code> */ private static boolean launchRserve(String cmd, int port) { return launchRserve(cmd, "--no-save --slave", "--no-save --slave", false, port); } /** * attempt to start Rserve. Note: parameters are <b>not</b> quoted, so avoid * using any quotes in arguments * * @param cmd command necessary to start R * @param rargs arguments are are to be passed to R * @param rsrvargs arguments to be passed to Rserve * @return <code>true</code> if Rserve is running or was successfully started, * <code>false</code> otherwise. */ private static boolean launchRserve(String cmd, String rargs, String rsrvargs, boolean debug, int port) { try { Process p; boolean isWindows = false; String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0, 7).equals("Windows")) { isWindows = true; /* Windows startup */ p = Runtime.getRuntime().exec("\"" + cmd + "\" -e \"library(Rserve);Rserve(" + (debug ? "TRUE" : "FALSE") + ",port=" + port + ",args='" + rsrvargs + "')\" " + rargs); } else /* unix startup */ { p = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "echo 'library(Rserve);Rserve(" + (debug ? "TRUE" : "FALSE") + ",port=" + port + ",args=\"" + rsrvargs + "\")'|" + cmd + " " + rargs }); } log.info("Starting new Rserve"); // we need to fetch the output - some platforms will die if you don't ... new RserveConsoleWriter(p.getErrorStream()); new RserveConsoleWriter(p.getInputStream()); if (!isWindows) /* on Windows the process will never return, so we cannot wait */ { p.waitFor(); } //System.out.println("StartRserve: call terminated, let us try to connect ..."); } catch (Exception x) { //System.out.println("StartRserve: failed to start Rserve process with " + x.getMessage()); return false; } int attempts = 5; /* try up to 5 times before giving up. We can be conservative here, because at this point the process execution itself was successful and the start up is usually asynchronous */ while (attempts > 0) { try { RConnection c = new RConnection(); c.close(); return true; } catch (Exception e) { //System.out.println("StartRserve: Try failed with: " + e.getMessage()); } /* a safety sleep just in case the start up is delayed or asynchronous */ try { Thread.sleep(500); } catch (InterruptedException ix) { }; attempts--; } return false; } /** * checks whether Rserve is running and if that's not the case it attempts to * start it using the defaults for the platform where it is run on. This * method is meant to be set-and-forget and cover most default setups. For * special setups you may get more control over R with * <<code>launchRserve</code> instead. */ public static boolean checkLocalRserve(int port) { if (isRserveRunning(port)) { log.info("Rserve already running"); return true; } String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0, 7).equals("Windows")) { //System.out.println("StartRserve: Windows: query registry to find where R is installed ..."); String installPath = null; try { Process rp = Runtime.getRuntime().exec("reg query HKLM\\Software\\R-core\\R"); WindowsRLocator regHog = new WindowsRLocator(rp.getInputStream()); rp.waitFor(); regHog.join(); installPath = regHog.getInstallPath(); } catch (Exception rge) { System.out.println("ERROR: unable to run REG to find the location of R: " + rge); return false; } if (installPath == null) { System.out.println("ERROR: canot find path to R. Make sure reg is available and R was installed with registry settings."); return false; } return launchRserve(installPath + "\\bin\\R.exe", port); } return (launchRserve("R", port) || /* try some common unix locations of R */ ((new File("/Library/Frameworks/R.framework/Resources/bin/R")).exists() && launchRserve("/Library/Frameworks/R.framework/Resources/bin/R", port)) || ((new File("/usr/local/lib/R/bin/R")).exists() && launchRserve("/usr/local/lib/R/bin/R", port)) || ((new File("/usr/lib/R/bin/R")).exists() && launchRserve("/usr/lib/R/bin/R", port)) || ((new File("/usr/local/bin/R")).exists() && launchRserve("/usr/local/bin/R", port)) || ((new File("/sw/bin/R")).exists() && launchRserve("/sw/bin/R", port)) || ((new File("/usr/common/bin/R")).exists() && launchRserve("/usr/common/bin/R", port)) || ((new File("/opt/bin/R")).exists() && launchRserve("/opt/bin/R", port))); } /** * check whether Rserve is currently running (on local machine and default * port). * * @return <code>true</code> if local Rserve instance is running, * <code>false</code> otherwise */ public static boolean isRserveRunning(int port) { try { RConnection c = new RConnection("127.0.0.1", port); c.close(); return true; } catch (Exception e) { //System.out.println("StartRserve: first connect try failed with: " + e.getMessage()); } return false; } }