/* * This file is part of JGrasstools (http://www.jgrasstools.org) * (C) HydroloGIS - www.hydrologis.com * * JGrasstools 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.jgrasstools.gui.spatialtoolbox.core; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.List; import org.jgrasstools.gears.io.geopaparazzi.geopap4.ETimeUtilities; import org.jgrasstools.gears.libs.exceptions.ModelsUserCancelException; import org.jgrasstools.gears.libs.logging.JGTLogger; import org.jgrasstools.gui.console.ConsoleMessageFilter; import org.jgrasstools.gui.console.IProcessListener; import org.jgrasstools.gui.console.ELogStyle; import oms3.CLI; /** * Executor of OMS scripts. * * @author Andrea Antonello (www.hydrologis.com) */ @SuppressWarnings("nls") public class StageScriptExecutor { public static final String ORG_JGRASSTOOLS_MODULES = "org.jgrasstools.modules"; private List<IProcessListener> listeners = new ArrayList<IProcessListener>(); private String classPath; private boolean isRunning = false; private String javaExec; private static String nl = "\n"; private StringBuilder logBuilder = new StringBuilder(); public StageScriptExecutor( File jgtLibsFolder ) throws Exception { /* * get java exec */ String javaHome = System.getProperty("java.home"); if (javaHome != null) { File java = new File(javaHome, "bin/java"); if (java.exists()) { javaExec = java.getAbsolutePath(); } else { java = new File(javaHome, "bin/java.exe"); if (java.exists()) { javaExec = java.getAbsolutePath(); } else { javaExec = null; } } } if (javaExec == null) { javaExec = "java"; // hope ti is in the path } // File javaFile = new File("/home/hydrologis/SOFTWARE/JAVA/JDKS/CURRENT/bin/java"); // javaExec = javaFile.getAbsolutePath(); // if (!javaFile.getAbsolutePath().equals("java")) { // javaExec = javaFile.getAbsolutePath(); // // javaExec = "\"" + javaFile.getAbsolutePath() + "\""; // } else { // javaExec = javaFile.getName(); // } /* * get libraries */ File[] jarFiles = jgtLibsFolder.listFiles(new FilenameFilter(){ public boolean accept( File dir, String name ) { return name.endsWith("jar"); } }); if (jarFiles == null) { jarFiles = new File[0]; } Arrays.sort(jarFiles, new Comparator<File>(){ public int compare( File o1, File o2 ) { if (o1.getName().startsWith("jgt-oms") && o2.getName().startsWith("jgt-")) { return -1; } if (o2.getName().startsWith("jgt-oms") && o1.getName().startsWith("jgt-")) { return 1; } if (o1.getName().startsWith("jgt-") && !o2.getName().startsWith("jgt-")) { return 1; } if (o2.getName().startsWith("jgt-") && !o1.getName().startsWith("jgt-")) { return -1; } return 0; } }); StringBuilder cpBuilder = new StringBuilder(); for( int i = 0; i < jarFiles.length; i++ ) { if (i == 0) { cpBuilder.append(jarFiles[i].getAbsolutePath()); } else { cpBuilder.append(File.pathSeparator).append(jarFiles[i].getAbsolutePath()); } } String classpathJars = "\"" + cpBuilder.toString() + File.pathSeparator + ".\""; classPath = classpathJars; } /** * Execute an OMS script. * * @param script * the script file or the script string. * @param internalStream * @param errorStream * @param loggerLevelGui * the log level as presented in the GUI, can be OFF|ON. This is * not the OMS logger level, which in stead has to be picked from * the {@link SpatialToolboxConstants#LOGLEVELS_MAP}. * @param ramLevel * the heap size to use in megabytes. * @param encoding * @return the process. * @throws Exception */ public Process exec( String sessionId, String script, final String loggerLevelGui, String ramLevel, String encoding ) throws Exception { File scriptFile = new File(script); if (!scriptFile.exists()) { // if the file doesn't exist, it is a script, let's put it into a // file scriptFile = File.createTempFile("omsbox_script_", ".oms"); BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(scriptFile)); bw.write(script); } finally { bw.close(); } } else { // it is a script in a file, read it to log it BufferedReader br = null; StringBuilder sb = new StringBuilder(); try { br = new BufferedReader(new FileReader(scriptFile)); String line = null; while( (line = br.readLine()) != null ) { sb.append(line).append(nl); } } finally { br.close(); } script = sb.toString(); } // tmp folder String tempdir = System.getProperty("java.io.tmpdir"); File omsTmp = new File(tempdir + File.separator + "oms"); if (!omsTmp.exists()) omsTmp.mkdirs(); List<String> arguments = new ArrayList<String>(); arguments.add(javaExec); // ram usage String ramExpr = "-Xmx" + ramLevel + "m"; arguments.add(ramExpr); if (encoding != null && encoding.length() > 0) { encoding = "-Dfile.encoding=" + encoding; arguments.add(encoding); } // modules jars // List<String> modulesJars = StageModulesManager.getInstance().getModulesJars(true); // StringBuilder sb = new StringBuilder(); // for( String moduleJar : modulesJars ) { // sb.append(File.pathSeparator).append(moduleJar); // } // String modulesJarsString = sb.toString().replaceFirst(File.pathSeparator, ""); // String resourcesFlag = "-Doms.sim.resources=\"" + modulesJarsString + "\""; // arguments.add(resourcesFlag); // all the arguments arguments.add("-cp"); arguments.add(classPath); arguments.add(CLI.class.getCanonicalName()); if (loggerLevelGui.equals(SpatialToolboxConstants.LOGLEVEL_GUI_ON)) { arguments.add("-l"); arguments.add("FINEST"); } arguments.add("-r"); arguments.add(scriptFile.getAbsolutePath()); // String tmpScriptFilesDir = System.getProperty("java.io.tmpdir"); // File tmpScriptFolder = new File(tmpScriptFilesDir); // StringBuilder runSb = new StringBuilder(); // for( String arg : arguments ) { // runSb.append(arg).append(" "); // } // // String[] args; // if (OsCheck.getOperatingSystemType() == OSType.Windows) { // File tmpRunFile = new File(tmpScriptFolder, "udig_spatialtoolbox_" + sessionId + ".bat"); // FileUtilities.writeFile("@echo off\n" + runSb.toString(), tmpRunFile); // args = new String[]{"cmd", "/c", tmpRunFile.getAbsolutePath()}; // } else { // File tmpRunFile = new File(tmpScriptFolder, "udig_spatialtoolbox_" + sessionId + ".sh"); // FileUtilities.writeFile(runSb.toString(), tmpRunFile); // args = new String[]{"sh", tmpRunFile.getAbsolutePath()}; // } // {javaFile, ramExpr, resourcesFlag, "-cp", classPath, // CLI.class.getCanonicalName(), "-r", // scriptFile.getAbsolutePath()}; JGTLogger.logDebug(this, "Execution arguments:"); for( String arg : arguments ) { JGTLogger.logDebug(this, arg); } ProcessBuilder processBuilder = new ProcessBuilder(arguments); // work in home // processBuilder.directory(homeFile); // environment // Map<String, String> environment = processBuilder.environment(); // environment.put("CLASSPATH", classPath); final Process process = processBuilder.start(); logBuilder.setLength(0); StringBuilder preCommentsBuilder = new StringBuilder(); preCommentsBuilder .append("Process started: " + SpatialToolboxConstants.dateTimeFormatterYYYYMMDDHHMMSS.format(new Date())); preCommentsBuilder.append(nl); // command launched if (loggerLevelGui.equals(SpatialToolboxConstants.LOGLEVEL_GUI_ON)) { preCommentsBuilder.append("------------------------------>8----------------------------" + nl); preCommentsBuilder.append("Launching command: " + nl); preCommentsBuilder.append("------------------" + nl); List<String> command = processBuilder.command(); for( String arg : command ) { preCommentsBuilder.append(arg); preCommentsBuilder.append(" "); } preCommentsBuilder.append("" + nl); preCommentsBuilder.append("(you can run the above from command line, customizing the content)" + nl); preCommentsBuilder.append("----------------------------------->8---------------------------------" + nl); preCommentsBuilder.append("" + nl); // script run preCommentsBuilder.append("Script run: " + nl); preCommentsBuilder.append("-----------" + nl); // remove datafolder reference preCommentsBuilder.append(script); preCommentsBuilder.append("" + nl); preCommentsBuilder.append("------------------------------>8----------------------------" + nl); preCommentsBuilder.append("" + nl); // // environment used // preCommentsBuilder.append("Environment used: " + nl); // preCommentsBuilder.append("-----------------" + nl); // // Set<Entry<String, String>> entrySet = environment.entrySet(); // for( Entry<String, String> entry : entrySet ) { // preCommentsBuilder.append(entry.getKey()); // preCommentsBuilder.append(" =\t"); // preCommentsBuilder.append(entry.getValue()).append("" + nl); // } // preCommentsBuilder.append("------------------------------>8----------------------------" // + nl); // preCommentsBuilder.append(""); } printMessage(preCommentsBuilder.toString(), ELogStyle.COMMENT); isRunning = true; new Thread(){ public void run() { BufferedReader br = null; try { InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); br = new BufferedReader(isr); String line; while( (line = br.readLine()) != null ) { printMessage(line, ELogStyle.NORMAL); } } catch (Exception e) { e.printStackTrace(); printException(loggerLevelGui, e); } finally { if (br != null) try { br.close(); } catch (IOException e) { e.printStackTrace(); } printMessage( "Process finished: " + SpatialToolboxConstants.dateTimeFormatterYYYYMMDDHHMMSS.format(new Date()), ELogStyle.COMMENT); isRunning = false; updateListenersForModuleStop(); } } }.start(); new Thread(){ public void run() { BufferedReader br = null; try { String userCanceled = ModelsUserCancelException.class.getCanonicalName(); InputStream is = process.getErrorStream(); InputStreamReader isr = new InputStreamReader(is); br = new BufferedReader(isr); String line; while( (line = br.readLine()) != null ) { /* * remove of ugly recurring geotools warnings. Not nice, * but at least users do not get confused. */ if (ConsoleMessageFilter.doRemove(line)) { continue; } if (line.startsWith(userCanceled)) { line = "Process cancelled by user."; } printMessage(line, ELogStyle.ERROR); } } catch (Exception e) { e.printStackTrace(); printException(loggerLevelGui, e); } finally { if (br != null) try { br.close(); } catch (IOException e) { e.printStackTrace(); } } }; }.start(); return process; } public boolean isRunning() { return isRunning; } public void addProcessListener( IProcessListener listener ) { if (!listeners.contains(listener)) { listeners.add(listener); } } public void removeProcessListener( IProcessListener listener ) { if (listeners.contains(listener)) { listeners.remove(listener); } } private synchronized void printMessage( String message, ELogStyle style ) { String[] split = message.split(nl); for( String string : split ) { for( IProcessListener listener : listeners ) { listener.onMessage(string, style); } } } private void updateListenersForModuleStop() { for( IProcessListener listener : listeners ) { listener.onProcessStopped(); } } private void printException( final String loggerLevelGui, Exception e ) { if (loggerLevelGui.equals(SpatialToolboxConstants.LOGLEVEL_GUI_ON)) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); printMessage(sw.toString(), ELogStyle.ERROR); } else { printMessage(e.getLocalizedMessage(), ELogStyle.ERROR); } } public void killProcess( Process process ) { if (process != null) { process.destroy(); try { process.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } } } }