[Remoterengine-commits] r189 - pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common

noreply at r-forge.r-project.org noreply at r-forge.r-project.org
Mon Sep 28 19:30:56 CEST 2009


Author: ian_long
Date: 2009-09-28 19:30:56 +0200 (Mon, 28 Sep 2009)
New Revision: 189

Added:
   pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/InputHandler.java
   pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/Launcher.java
   pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/ProcessStreamHandler.java
Log:
Classes to support launching the server from Java

Added: pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/InputHandler.java
===================================================================
--- pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/InputHandler.java	                        (rev 0)
+++ pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/InputHandler.java	2009-09-28 17:30:56 UTC (rev 189)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, Ian Long <ilong at stoatsoftware.com>
+ *
+ * This file is part of the RemoteREngine project
+ *
+ * The RemoteREngine project is free software: 
+ * you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The RemoteREngine project is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the RemoteREngine project. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.rosuda.REngine.remote.common;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+/**
+ * Class to intercept console input and redirect it to an internal process 
+ * @author Ian
+ */
+public class InputHandler implements Runnable {
+	/** Internal flag to stop the thread */
+	private boolean run = true;
+	/** Reader for the console */
+	private BufferedReader in = null;
+	/** Stream to direct any input to */
+	private OutputStream output = null;
+	
+	/**
+	 * Initialise the handler, defining the input stream that this thread
+	 * redirects any StdIn input to
+	 * @param output Stream to pass the console input to
+	 */
+	public InputHandler(OutputStream output) {
+		in = new BufferedReader(	new InputStreamReader(System.in) );
+		this.output = output;
+	}
+
+	/**
+	 * Main method for the handler which passes console input into the main processing
+	 */
+	public void run() {
+	
+		String res = null;
+		while (run) {
+			try{
+				res = in.readLine() ;
+				if (res.equals("Quit")) {
+					System.out.println(this.getClass().getName() + " preparing to close");
+					run = false;
+				}
+				res = res + "\n";	// Put on the line feed because readLine strips it off
+				if (output != null) {	// output may be null if there is a start up problem
+					output.write(res.getBytes());
+					output.flush();
+				}
+			} catch( IOException e){
+				System.err.println(this.getClass().getName() + " ERROR: " + e.getMessage());
+			}
+		}
+		close();
+	}
+
+	/**
+	 * Shut down this thread cleanly
+	 */
+	public void close() {
+		System.out.println(this.getClass().getName() + " stop requested");
+		run = false;
+		try {
+			output.flush();
+			output.close();
+		} catch (Exception e) {
+			System.err.println(this.getClass().getName() + " Error closing stream");
+		} finally {
+			output = null;
+			System.out.println(this.getClass().getName() + " shut down");
+		}
+	}
+}
\ No newline at end of file


Property changes on: pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/InputHandler.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Revision Author HeadURL Id

Added: pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/Launcher.java
===================================================================
--- pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/Launcher.java	                        (rev 0)
+++ pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/Launcher.java	2009-09-28 17:30:56 UTC (rev 189)
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2009, Ian Long <ilong at stoatsoftware.com>
+ *
+ * This file is part of the RemoteREngine project
+ *
+ * The RemoteREngine project is free software: 
+ * you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The RemoteREngine project is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the RemoteREngine project. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.rosuda.REngine.remote.common;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.EmptyStackException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Helper class to set the environment and then launch the server process
+ * @author $Author$
+ * @version $Rev$ as of $Date$
+ * <p>URL : $HeadURL$
+ */
+public class Launcher {
+	/** Key for the JAVA_HOME environment variable / system property */
+	public static final String JAVA_HOME = "JAVA_HOME";
+	/** Key for the system property identifying the java executable */
+	public static final String JAVACMD = "JAVACMD";
+	/** Key for the R_HOME environment variable / system property */
+	public static final String R_HOME = "R_HOME";
+	/** Key for the System property identifying the R Share directory */
+	public static final String R_SHARE = "R_SHARE";
+	/** Key for the System property identifying the R include directory */
+	public static final String R_INCLUDE_DIR = "R_INCLUDE_DIR";
+	/** Key for the System property identifying the R document directory */
+	public static final String R_DOC_DIR = "R_DOC_DIR";
+	/** Key for the System property / Environment variable identifying the library load path */
+	public static final String LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
+	/** Key for the environment variable / System property identifying the locale */ 
+	public static final String LC_NUMERIC = "LC_NUMERIC";
+	/** Key for the System property for NO_SIG */
+	public static final String NO_SIG = "NO_SIG";
+	/** Key for the System property to identify the default R packages to be loaded */
+	public static final String R_DEFAULT_PACKAGES = "R_DEFAULT_PACKAGES";
+	
+	/** Define the default class that this program will try and launch */
+	public static final String DEFAULT_STARTCLASS = "org.rosuda.REngine.remote.server.REngineServer";
+	/** Define the default amount of memory that will be allocated to the process launched */
+	public static final String DEFAULT_MEMORYSIZE = "mx1024M";
+	/** Define the default jar file to be referenced during the launch */
+	public static final String SERVER_JARFILE = "RemoteREngine-server.jar";
+	/** Default list of packages to be loaded when the server starts */
+	public static final String[] DEFAULT_PACKAGES = new String[] {"utils", "stats", "rJava", "methods", "grDevices", 
+		"graphics", "datasets"};
+	/** Internal cache of the system properties */
+	protected Properties systemProps = System.getProperties();
+	/** Internal store for the command line arguments from the launcher */
+	protected String[] args;
+	/** Flag to indicate whether verbose output should be produced during launch */
+	protected boolean verbose = false;
+	/** Flag to indicate that the launcher should be run in test mode - i.e. not launch the process */
+	protected boolean testMode = false;
+	/** Warning string constructed while processing and checking the environment */
+	protected StringBuilder warning = new StringBuilder();
+
+	/**
+	 * Print a list of the menu options to StdOut. This can be activated by the '-h' option on the command line
+	 * @param exit Should the JVM shut down after printing the message
+	 */
+	private void printMenu(boolean exit) {
+		StringBuilder menu = new StringBuilder();
+		menu.append(this.getClass().getName() + " command line options:");
+		menu.append("\nLauncher -v -h -b path -c class -XMemoryDefinition <System Properties>");
+		menu.append("\n\t-h: Print this menu");
+		menu.append("\n\t-v: Verbose mode; default false");
+		menu.append("\n\t-X: Java process memory defintion; default " + DEFAULT_MEMORYSIZE);
+		menu.append("\n\t-b: Path to root of class files (instead of " + SERVER_JARFILE + " file");
+		menu.append("\n\t-c: Class to be launched; default " + DEFAULT_STARTCLASS);
+		menu.append("\n\t-D<propertyname>=<propertyvalue>: Set System property");
+		menu.append("\n\t-t: Test mode - write out the launch command but do not execute it");
+		System.out.println(menu.toString());
+		if (exit) System.exit(0);
+	}
+	
+	/**
+	 * Check the required environment settings and construct the command to launch the server.
+	 * @see #printMenu(boolean)
+	 * @param javaCmd Path to the java executable
+	 * @return Components of the command to launch the server
+	 */
+	public Vector<String> buildLaunchCommand(String javaCmd) {
+		String startClass = DEFAULT_STARTCLASS;
+		String memorySize = DEFAULT_MEMORYSIZE;
+		Properties newProperties = new Properties();
+
+		String buildDirPath = null;		// Root directory for the build directory of the project source
+		boolean useJarFiles = true;		// The alternative would use the .class files directly
+		Vector<String> argVector = new Vector<String>();
+		Stack<String> orginalArgs = new Stack<String>();
+		for (int i = args.length-1; i >= 0; i--) { // populate the stack in reverse order
+			if (args[i].equals("-v")) verbose = true;
+			else if (args[i].equals("-h")) printMenu(true);
+			else if (args[i].equals("-t")) testMode = true;
+			else
+				orginalArgs.push(args[i]);
+		}
+		
+		// Parse the command line arguments
+		while (true) {
+			try {
+				String arg = orginalArgs.pop();
+				if (arg.equals("-b")) {
+					buildDirPath = orginalArgs.pop();
+					if (buildDirPath == null) {
+						warning.append("Incomplete build path set using -b option");
+					} else {
+						File buildDir = new File(buildDirPath);
+						if (buildDir.exists() && buildDir.isDirectory()) {
+							useJarFiles = false;
+						} else {
+							warning.append("Build path set with -b option must reference a directory");
+						}
+					}
+				} else if (arg.startsWith("-X")) memorySize = arg.substring(2);
+				else if (arg.startsWith("-c")) startClass = orginalArgs.pop();
+				else if (arg.startsWith("-D")) {
+					if (arg == null || arg.length() < 3) {
+						warning.append("System properties must be set as -D<systemproperty>=<propertyvalue> e.g. -Djava.home=/usr/home/me\n");
+					} else {
+						StringTokenizer tokenizer = new StringTokenizer(arg.substring(2),"=");
+						if (tokenizer.countTokens() != 2) 
+							warning.append("System properties must be set as -D<systemproperty>=<propertyvalue> e.g. -Djava.home=/usr/home/me\n");
+						else {
+							String property = tokenizer.nextToken();
+							String value = tokenizer.nextToken();
+							systemProps.setProperty(property,value);
+							newProperties.setProperty(property,value);
+						}
+					}
+				} else {
+					argVector.add(arg);
+				}
+			} catch (EmptyStackException e) { break; }
+		}
+		
+		String[] arguments = argVector.toArray(new String[0]);
+		
+		
+		// Check R_HOME is set
+		String rHomeString = findProperty(R_HOME);
+		if (rHomeString == null) {
+			warning.append(R_HOME + " must be set to the path of the R installation\n");
+		} else {
+			File rhome = new File(rHomeString);
+			if (!rhome.exists()) {
+				warning.append(R_HOME + " environment must be set to a valid directory; currently set to '" + rHomeString + "'\n");
+			}
+		}
+		if (verbose) System.out.println("R_HOME: " + rHomeString);
+		
+		// Define R_SHARE_DIR, R_INCLUDE_DIR,R_DOC_DIR
+		String rShare = filePath(new String[] {rHomeString,"share"});
+		systemProps.setProperty(R_SHARE, rShare);
+		if (verbose) System.out.println(R_SHARE + ": " + rShare);
+		String rInclude = filePath(new String[]{rHomeString, "include"});
+		systemProps.setProperty(R_INCLUDE_DIR, rInclude);
+		if (verbose) System.out.println(R_INCLUDE_DIR + ": " + rInclude);
+		String rDoc = filePath(new String[]{rHomeString, "doc"});
+		systemProps.setProperty(R_DOC_DIR, rDoc);
+		if (verbose) System.out.println(R_DOC_DIR + ": " + rDoc);
+		
+		// Define R_DEFAULT_PACKAGES
+		StringBuilder packages = new StringBuilder();
+		for (String packagename : DEFAULT_PACKAGES) {
+			packages.append(packagename + ", ");
+		}
+		String rPackages = "";
+		if (packages.length() > 0) rPackages = packages.substring(0, packages.length() - 1); 
+		systemProps.setProperty(R_DEFAULT_PACKAGES, rPackages);
+		if (verbose) System.out.println(R_DEFAULT_PACKAGES + ": " + rPackages);
+
+		// Set JRI_LD_PATH
+		String jriPath = "";
+		try {
+			jriPath = locateFile("jri", rHomeString);
+		} catch (FileNotFoundException e) {
+			warning.append("Unable to locate jri directory: " + e.getMessage() + "\n");
+		} catch (IOException e) {
+			warning.append(e.getClass().getName() + " while trying to locate jri directory: " + e.getMessage() + "\n");
+		}
+		String jriPaths = mergePaths(jriPath, filePath(rHomeString,"bin"), filePath(rHomeString,"lib"));
+		String ldPath = findProperty(LD_LIBRARY_PATH);
+		// TODO Ensure jriPath is only included in the path once
+		String fullLDPath = (ldPath == null || ldPath.length()==0) ? jriPaths : mergePaths(jriPaths,ldPath);
+		systemProps.setProperty(LD_LIBRARY_PATH,	fullLDPath);
+		if (verbose) System.out.println(LD_LIBRARY_PATH + ": " + fullLDPath);
+		
+		systemProps.setProperty(LC_NUMERIC, "C");
+		if (verbose) System.out.println(LC_NUMERIC + ": " + findProperty(LC_NUMERIC));
+		systemProps.setProperty(NO_SIG,"1");
+		if (verbose) System.out.println(NO_SIG + ": " + findProperty(NO_SIG));
+		
+		String rLibrary = "";
+		String rJava = "";
+		String remoteRServer = "";
+		try {
+			rLibrary = locateFile("library",rHomeString);
+			rJava = locateFile("rJava",rLibrary);
+			remoteRServer = locateFile("RemoteREngine",rLibrary);
+		} catch (IOException e) {
+			warning.append(e.getClass().getName() + " looking for rJava or RemoteREngine installation directories\n");
+		}
+		String rJavaClasspath = buildRJavaClassPath( rJava, false);
+		String classpath = buildClasspath(rHomeString, rJava, useJarFiles, buildDirPath, false);
+		String codebase = buildClasspath(rHomeString, rJava, useJarFiles, buildDirPath, true);
+		
+		if (verbose) System.out.println("Classpath: " + classpath);
+		if (verbose) System.out.println("RMI Codebase: " + codebase);
+
+		String policyFile = "";
+		try {
+			policyFile = locateFile("server.policy", remoteRServer);
+		} catch (IOException e) {
+			warning.append(e.getClass().getName() + " while locating security policy file\n");
+		}
+		if (verbose) System.out.println("Policy file: " + policyFile);
+
+		if (warning.length() > 0) {
+			System.err.println("Environment set up failed:\n");
+			System.err.println(warning.toString());
+			return new Vector<String>(0);
+		} 
+
+		// Environment is checked and passed
+		System.setProperties(systemProps);
+		Vector<String> command = new Vector<String>();
+		command.add(javaCmd);
+		command.add("-X" + memorySize);
+		command.add("-classpath");
+		command.add(classpath);
+		command.add("-Djava.library.path=" + findProperty(LD_LIBRARY_PATH));
+		command.add("-Drjava.class.path=" + rJavaClasspath);
+		command.add("-Djava.rmi.server.codebase=" + codebase);
+		command.add("-Djava.security.policy=" + policyFile);
+		if (newProperties.size() > 0) {
+			for (Object newProperty : newProperties.keySet()) {
+				command.add("-D" + newProperty + "=" + newProperties.getProperty((String)newProperty));
+			}
+		}
+		command.add(startClass);
+		if (arguments.length > 0) {
+			for (String arg : arguments) command.add(arg);
+		}
+		return command;
+	}
+	
+	/**
+	 * Method to search along JAVA_HOME to locate the executable for java
+	 * @return Fully qualified path to java
+	 */
+	private String findJava() {
+		// Check JAVA_HOME
+		String javaHomeString = findProperty(JAVA_HOME);
+		if (javaHomeString == null) {
+			warning.append(JAVA_HOME + " must be set to the path of the Java installation\n");
+		} else {
+			File javahome = new File(javaHomeString);
+			if (!javahome.exists()) {
+				warning.append(JAVA_HOME + " environment must be set to a valid directory; currently set to '" + javaHomeString + "'\n");
+			}
+		}
+		if (verbose) System.out.println(JAVA_HOME + ": " + javaHomeString);
+
+		String javaCmd = "";
+		try {
+			javaCmd = locateJava(javaHomeString);
+		} catch (IOException e) {
+			warning.append(e.getClass().getName() + " while locating Java command relative to '" + javaHomeString + "'\n");
+		}
+			
+		if (javaCmd.length() == 0) {
+			warning.append("Unable to locate java executable, searching below '" + javaHomeString + "'\n");
+		}
+		systemProps.setProperty(JAVACMD, javaCmd);
+		if (verbose) System.out.println(JAVACMD + ": " + javaCmd);
+		
+		return javaCmd;
+	}
+	
+	/**
+	 * Helper method to build the path to the rJava java files
+	 * @param rJava Path to the rJava installation
+	 * @param convertToCodebase Flag to determine if path should be converted to RMI codebase syntax
+	 * @return classpath components for rJava
+	 */
+	private String buildRJavaClassPath(String rJava, boolean convertToCodebase) {
+		try {
+			String rJavaBoot = (convertToCodebase ? "file:" : "") + filePath(new String[] {rJava,"java","boot"},true);
+			String rJavaPath = (convertToCodebase ? "file:" : "") + filePath(new String[] {rJava,"java"},true);
+			String rJavaClasspath = mergePaths(rJavaBoot,rJavaPath);
+			if (convertToCodebase) {
+				rJavaClasspath = rJavaClasspath.replace("\\", "/");
+				rJavaClasspath = rJavaClasspath.replace(";", ":");
+			}
+			return rJavaClasspath;
+		} catch (FileNotFoundException e) {
+			warning.append("Unable to locate rJava classpath directories\n");
+		}
+		return "";
+	}
+	
+	/**
+	 * Construct the classpath for the java launch
+	 * @param remoteRServer Path to the installation directory for RemoteREngine
+	 * @param useJarFiles Flag to indicate whether the server jar file or class files should be referenced
+	 * @param buildDirPath Path to the root of the java class files
+	 * @param convertToCodebase Flag to determine whether classpath should be converted to RMI codebase syntax
+	 * @return full path
+	 */
+	private String buildClasspath(String remoteRServer, String rJava, boolean useJarFiles, String buildDirPath, boolean convertToCodebase) {
+		Vector<String> classpath = new Vector<String>();
+		
+		try {
+			if (useJarFiles) {
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile(SERVER_JARFILE, remoteRServer));
+			} else {
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile("annotations",buildDirPath) + "\\");
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile("client",buildDirPath) + "\\");
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile("common",buildDirPath) + "\\");
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile("server",buildDirPath) + "\\");
+				classpath.add((convertToCodebase ? "file:" : "") + locateFile("stubs",buildDirPath) + "\\");
+				classpath.add((convertToCodebase ? "file:" : "") + buildDirPath + "\\");
+			}
+		} catch (IOException e) {
+			warning.append(e.getClass().getName() + " while building classpath\n");
+		}
+		
+		// We don't need to include the rJava path within the RMI Codebase
+		if (!convertToCodebase) classpath.add(buildRJavaClassPath(rJava, convertToCodebase));
+		String classpathStr = mergePaths(classpath.toArray(new String[0]));
+		if (convertToCodebase) {
+			classpathStr = classpathStr.replace("\\", "/");
+			classpathStr = classpathStr.replace(";", ":");
+		}
+		return classpathStr;
+	}
+
+	/**
+	 * Search for the Java executable within the supplied list of
+	 * path locations
+	 * @param javaHomeString Starting point for all the searches, the Java Home Directory
+	 * @return String containing the path or an empty String
+	 * @throws IOException Error checking directory location
+	 */
+	private String locateJava(String javaHomeString) throws IOException {
+		String javaCmd = findProperty(JAVACMD);
+		if (javaCmd.equals("")) {
+			// IBM's JDK on AIX uses strange locations for the executables
+			Vector<String[]> searchLocations = new Vector<String[]>(7);
+			searchLocations.add(new String[] {javaHomeString, "jre", "sh"});
+			searchLocations.add(new String[] {javaHomeString, "jre", "bin"});
+			searchLocations.add(new String[] {javaHomeString, "bin"});
+			searchLocations.add(new String[] {javaHomeString, "jre", "bin"});
+			searchLocations.add(new String[] {javaHomeString, "bin"});
+			searchLocations.add(new String[] {javaHomeString, "jre", "bin"});
+			
+			String[] fileMatch = new String[] {"java","java.exe"};
+			for (String[] searchPath : searchLocations) {
+				try {
+					javaCmd = locateFile(fileMatch, searchPath);
+				} catch (FileNotFoundException e) {
+					// Don't need to do anything 
+				}
+				// have located it
+				if (javaCmd.length() > 0) break;
+			}
+		}
+		return javaCmd;
+	}
+	
+	/**
+	 * Method to locate a file or directory starting from a known path on the system
+	 * @param target End of the filename or directory name to be searched for
+	 * @param start Path to the directory to start checking from
+	 * @return Fully qualified path to the file or directory if found
+	 * @throws FileNotFoundException Unable to locate file or supplied information was null
+	 * @throws IOException Error interpreting path information
+	 */
+	private String locateFile(String target, String start) throws FileNotFoundException, IOException {
+		return locateFile(new String[]{target}, new String[]{start});
+	}
+	
+	/**
+	 * Method to locate a file or directory starting from a known path on the system
+	 * @param targets End of the filename or directory name to be searched for
+	 * @param start Path to the directory to start checking from
+	 * @return Fully qualified path to the file or directory if found
+	 * @throws FileNotFoundException Unable to locate file or supplied information was null
+	 * @throws IOException Error interpreting path information
+	 */
+	private String locateFile(String[] targets, String[] start) throws FileNotFoundException, IOException {
+		if (targets == null || targets.length == 0) throw new FileNotFoundException("Target not defined");
+		if (start == null || start.length == 0) throw new FileNotFoundException("Start not defined");
+		Stack<File>directoriesToCheck = new Stack<File>();
+		File startingPoint = new File(filePath(start));
+		directoriesToCheck.push(startingPoint);
+		if (startingPoint == null || !startingPoint.exists()) throw new FileNotFoundException("Unable to find '" + startingPoint +"'");
+		boolean found = false;
+		while (directoriesToCheck.size() > 0 && !found) {
+			File currentDir = directoriesToCheck.pop();
+			File[] dirFiles = currentDir.listFiles();
+			for (File file : dirFiles) {
+				for (String target : targets) {
+					if (file.getAbsolutePath().endsWith(target)) {
+						return file.getAbsolutePath();
+					}
+				}
+				if (file.isDirectory()) directoriesToCheck.push(file);
+			}
+		}
+		throw new FileNotFoundException("Unable to locate '" + targets + "' beneath '" + start + "'");
+	}
+	
+	/**
+	 * Method to combine a series of paths together into a single string using path separator 
+	 * character for the current operating system. This method will return an empty string if 
+	 * insufficient information is passed into it.
+	 * @param paths Paths to be combined together
+	 * @return Combined path
+	 */
+	private String mergePaths(String... paths) {
+		return mergePaths(paths,findProperty("path.separator"));
+	}
+
+	/**
+	 * Method to combine a series of paths together into a single string using the supplied
+	 * path separator character. This method will return an empty string if insufficient
+	 * information is passed into it.
+	 * @param paths Paths to be combined together
+	 * @param pathSep
+	 * @return Combined path
+	 */
+	private String mergePaths(String[] paths, String pathSep) {
+		if (paths == null || pathSep == null) return "";
+		StringBuilder fullPath = new StringBuilder();
+		for (String path : paths) {
+			if (path != null && path.length() > 0) {
+				fullPath.append(path);
+				fullPath.append(pathSep);
+			}
+		}
+		
+		return (fullPath.length() > 0) ? fullPath.substring(0, fullPath.length() -1) : "";
+	}
+	
+	/**
+	 * Concatenate a series of path elements together
+	 * @param elements path elements to be combined together
+	 * @return Single path element containing all the entries supplied
+	 */
+	private String filePath(String... elements) {
+		try {
+			return filePath(elements, findProperty("file.separator"),false);
+		} catch (FileNotFoundException e) {
+			// we should never get here
+			throw new RuntimeException("Unknown error within filePath",e);
+		}
+	}
+	
+	/**
+	 * Combine a series of sub-directory locations together to form a path
+	 * using the file separator supplied
+	 * @param elements Sub-directories to be joined together
+	 * @param check Flag to indicate whether to check if the resultant path exists
+	 * @return Path string Combined path
+	 * @throws FileNotFoundException If checking and failed to find the path
+	 */
+	private String filePath(String[] elements, boolean check) throws FileNotFoundException {
+		return filePath(elements, findProperty("file.separator"),check);
+	}
+	
+	/**
+	 * Combine a series of sub-directory locations together to form a path
+	 * using the file separator supplied
+	 * @param elements Sub-directories to be joined together
+	 * @param sep Character to be used as the file separator
+	 * @param check Flag to indicate whether to check if the resultant path exists
+	 * @return Path string Combined path
+	 * @throws FileNotFoundException If checking and failed to find the path
+	 */
+	private String filePath(String[] elements, String sep, boolean check) throws FileNotFoundException {
+		StringBuilder path = new StringBuilder();
+		for (String element : elements) {
+			path.append(element);
+			path.append(sep);
+		}
+		String fullPath = (path.length() > 0)? path.substring(0, path.length()-1) : "";
+		if (check) {
+			File file = new File(fullPath);
+			if (!file.exists()) throw new FileNotFoundException(fullPath + " does not exist");
+		}
+		return fullPath;
+	}
+	
+	private String findProperty(String propertyName) {
+		if (systemProps.containsKey(propertyName)) return systemProps.getProperty(propertyName);
+
+		Map<String, String> environment = System.getenv();
+/*		if (verbose) {
+			for (String key : environment.keySet()) 
+				System.out.println(key + ": " + environment.get(key));
+		}
+*/
+		if (environment.containsKey(propertyName)) return environment.get(propertyName);
+		if (verbose) System.out.println("Unable to find property for '" + propertyName + "'");
+		return "";
+	}
+
+	/**
+	 * Start the program
+	 * @param args Command line arguments @see #buildLaunchCommand()
+	 */
+	public static void main(String[] args) {
+		Launcher launcher = new Launcher(args);
+		String javaCmd = launcher.findJava();
+		Vector<String> launchCommand = launcher.buildLaunchCommand(javaCmd);
+		if (launcher.verbose) {
+			System.out.println("\nCommand: ");
+			for (String component : launchCommand) {
+				System.out.println(component);
+			}
+		}
+
+		if (launcher.isTestMode() ) {
+			if (!launcher.verbose) {// verbose mode already writes the command out
+				System.out.println("\nCommand: ");
+				StringBuilder builder = new StringBuilder();
+				for (String component : launchCommand) {
+					System.out.println(component);
+					builder.append(component + " ");
+				}
+				File launchfile = null;
+				BufferedWriter bw = null;
+				try {
+					launchfile = new File("launchcommand.txt");
+					bw = new BufferedWriter(new FileWriter(launchfile));
+					bw.write(builder.toString() + "\n");
+				} catch (IOException e) {
+					System.err.println(e.getClass().getName() + " writing command to " + launchfile.getAbsolutePath() +
+							": " + e.getMessage());
+				} finally {
+					try {
+						bw.flush();
+						bw.close();
+					} catch (Exception e) {}
+				}
+			}	
+		} else {
+			System.out.println("Launcher classpath: " + System.getProperty("java.class.path"));
+			Runtime runtime = Runtime.getRuntime();
+			ProcessStreamHandler stdOutHandler = null;
+			ProcessStreamHandler stdErrHandler = null;
+			InputHandler stdInHandler = null;
+			try {
+				BufferedReader in = new BufferedReader(new InputStreamReader(System.in) );
+
+				Process process = runtime.exec(launchCommand.toArray(new String[0]));
+				stdOutHandler = new ProcessStreamHandler(process.getInputStream());
+				stdErrHandler = new ProcessStreamHandler(process.getErrorStream());
+				stdInHandler = new InputHandler(process.getOutputStream());
+				OutputStream os = process.getOutputStream();
+				
+				Thread stdOutThread = new Thread(stdOutHandler,"stdOutHandler");
+				Thread stdErrThread = new Thread(stdErrHandler,"stdErrHandler");
+				Thread stdInThread = new Thread(stdInHandler,"stdInHandler");
+				
+				stdOutThread.start();
+				stdErrThread.start();
+				stdInThread.start();
+				
+	            int exitVal = process.waitFor();
+	            System.out.println("ExitValue: " + exitVal);
+				
+			} catch (Throwable e) {
+				System.err.println(e.getClass().getName() + " while running server; " + e.getMessage());
+			} finally {
+				if (stdOutHandler != null) stdOutHandler.close();
+	            if (stdErrHandler != null) stdErrHandler.close();
+	            if (stdInHandler != null) stdInHandler.close();
+			}
+		}
+	}
+	
+	/**
+	 * Public constructor
+	 * @param args Command line arguments @see #buildLaunchCommand()
+	 */
+	public Launcher(String[] args) {
+		this.args=args;
+	}
+
+	/**
+	 * Return whether or not this launcher is running in test mode - within test mode it only
+	 * prints out the command to run the process rather than try and run it.
+	 * @return true if running within test mode.
+	 */
+	public boolean isTestMode() {
+		return testMode;
+	}
+}


Property changes on: pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/Launcher.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Revision Author HeadURL Id

Added: pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/ProcessStreamHandler.java
===================================================================
--- pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/ProcessStreamHandler.java	                        (rev 0)
+++ pkg/RemoteREngine/inst/java_src/src/common/org/rosuda/REngine/remote/common/ProcessStreamHandler.java	2009-09-28 17:30:56 UTC (rev 189)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2009, Ian Long <ilong at stoatsoftware.com>
+ *
+ * This file is part of the RemoteREngine project
+ *
+ * The RemoteREngine project is free software: 
+ * you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The RemoteREngine project is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the RemoteREngine project. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.rosuda.REngine.remote.common;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+/**
+ * @author $Author$
+ * @version $Rev$ as of $Date$
+ * <p>URL : $HeadURL$
+ */
+public class ProcessStreamHandler implements Runnable {
+	/** Define the stream this process is going to be handling */
+	private InputStream inputStream;
+	/** Define the stream this process is going to write out to */
+	private OutputStream outputStream;
+	
+	/**
+	 * Construct a stream handler, otherwise output is directed to StdOut
+	 * @param intputStream
+	 */
+	ProcessStreamHandler(InputStream intputStream ) {
+		this(intputStream, null);
+	}
+
+	/**
+	 * Construct stream handler defining the source and the output streams
+	 * @param inputStream Stream to be handled by this process
+	 * @param outputStream Stream to write output to
+	 */
+	ProcessStreamHandler(InputStream inputStream, OutputStream outputStream) {
+		this.inputStream = inputStream;
+		this.outputStream = outputStream;
+	}
+
+	ProcessStreamHandler(InputStream inputStream, String outputFilename, boolean append) {
+		this.inputStream = inputStream;
+		try {
+			this.outputStream = new FileOutputStream(outputFilename, append);
[TRUNCATED]

To get the complete diff run:
    svnlook diff /svnroot/remoterengine -r 189


More information about the Remoterengine-commits mailing list