2012-08-28 91 views
2

我想從一個java程序中運行一個groovy腳本作爲一個單獨的進程(爲了避免jar衝突問題)。如何從Java運行groovy作爲一個獨立的進程?

這是我到目前爲止有:

public static void runGroovyScript(Path scriptPath, String... args) { 
    try { 
     List<String> argsList = newArrayList(); 
     argsList.add("groovy"); 
     argsList.add(scriptPath.toAbsolutePath().toString()); 
     Collections.addAll(argsList, args); 

     Process process = Runtime.getRuntime().exec(argsList.toArray(new String[argsList.size()])); 
     // Note - out input is the process' output 
     String input = Streams.asString(process.getInputStream()); 
     String error = Streams.asString(process.getErrorStream()); 

     logger.info("Groovy output for " + Arrays.toString(args) + "\r\n" + input); 
     logger.info("Groovy error for " + Arrays.toString(args) + "\r\n" + error); 

     int returnValue = process.waitFor(); 
     if (returnValue != 0) { 
      throw new RuntimeException("Groovy process returned " + returnValue); 
     } 
    } catch (Throwable e) { 
     throw new RuntimeException("Failure running build script: " + scriptPath + " " + Joiner.on(" ").join(args), e); 
    } 
} 

的問題,當然,是groovy沒有一個公認的命令。它由於環境變量PATH而從命令行運行,並解決了cmd.exe的問題。在Linux上,有一個不同的解決機制。什麼是尋找groovy可執行文件的平臺無關的方式,以便將它傳遞給Runtime.exec()

+0

我認爲這應該回答你的問題:http://stackoverflow.com/questions/378905/how-to-invoke-groovy-with-java-from-command-line –

+0

@SamuelAudet - 我不確定它確實。 – ripper234

+0

好吧,也許你不熟悉'java.home'系統屬性,它包含'bin'目錄下的'java'可執行文件? –

回答

0

實際上,我們與其他類加載器擺弄,但沒有雪茄。我們所做的是定義在系統變量的常規exeuctable的位置,並添加「CMD/C」爲Windows:

import com.google.common.base.Joiner; 
import org.apache.commons.lang.SystemUtils; 
import org.apache.log4j.Logger; 

import java.nio.file.Path; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 

import static com.google.common.collect.Lists.newArrayList; 
import static org.apache.ivy.util.Checks.checkNotNull; 

public class GroovyRunner { 
    private final static Logger logger = LoggerHelper.getLogger(); 

    public static void runGroovyScript(Path scriptPath, String... args) { 
     try { 
      List<String> argsList = newArrayList(); 
      String groovyPath = System.getenv("PLAY_GROOVY_PATH"); 

      if (SystemUtils.IS_OS_WINDOWS) { 
       // Window, no easy default for PLAY_GROOVY_PATH 
       checkNotNull(groovyPath, "Missing Env Var 'PLAY_GROOVY_PATH'"); 

       argsList.add("cmd"); 
       argsList.add("/c"); 
       argsList.add(groovyPath); 
      } else { 
       if (groovyPath == null) { 
        // Provide a reasonable default for linux 
        groovyPath = "/usr/bin/groovy"; 
       } 
       argsList.add(groovyPath); 
      } 

      argsList.add(scriptPath.toAbsolutePath().toString()); 
      Collections.addAll(argsList, args); 

      String join = Collections3.join(argsList, " "); 

      ExecCommand process = new ExecCommand(join); 

      // Note - out input is the process' output 
      String output = process.getOutput(); 
      String error = process.getError(); 

      logger.info("Groovy output for " + Arrays.toString(args) + "\r\n" + output); 
      logger.info("Groovy error for " + Arrays.toString(args) + "\r\n" + error); 


      if (process.getReturnValue() != 0) { 
       throw new RuntimeException("Groovy process returned " + process.getReturnValue()); 
      } 
     } catch (Throwable e) { 
      throw new RuntimeException("Failure running groovy script: " + scriptPath + " " + Joiner.on(" ").join(args), e); 
     } 
    } 
} 
1

乾淨的方法是將可執行文件的絕對路徑作爲某種配置參數傳遞給應用程序。

您也可以解析PATH環境變量和搜索自己,但是:

  • 不同的平臺可以有不同的機制如何尋找可執行文件。例如,他們使用不同的path separator characters,您需要處理該問題。
  • 這是一種安全問題。攻擊者可能會傳遞給您的程序PATH指向名爲groovy的惡意程序的環境變量。

我建議採取不同的方法。你可以使用一個單獨的ClassLoader來加載你的groovy腳本。 Advanages:

  1. 您將避免JAR碰撞問題。
  2. 但是你不需要產生任何外部進程。
  3. 您還可以使用自定義SecurityManager來限制腳本允許執行的操作。
  4. 您可以更好地與腳本進行通信 - 使用方法調用而不僅僅是stdin/out。

參見:


你也可以使用Java腳本API相結合。這也許是最強大和靈活的解決方案。對於這一點,看到

+0

我們實際上弄亂了另一個類裝載器,但沒有雪茄。我們所做的是在系統變量中定義groovy exeuctable的位置,併爲Windows添加「cmd/c」。我將發佈我們的代碼作爲答案。 – ripper234

相關問題