如何将groovy作为一个单独的进程从Java运行?

如何将groovy作为一个单独的进程从Java运行?,java,groovy,process,Java,Groovy,Process,我试图在java程序中作为一个单独的进程运行groovy脚本(以避免jar冲突问题) 这就是我到目前为止所做的: public static void runGroovyScript(Path scriptPath, String... args) { try { List<String> argsList = newArrayList(); argsList.add("groovy"); argsList.add(script

我试图在java程序中作为一个单独的进程运行groovy脚本(以避免jar冲突问题)

这就是我到目前为止所做的:

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);
    }
}
publicstaticvoid runGroovyScript(路径scriptPath,字符串…args){
试一试{
List argsList=newArrayList();
argsList.add(“groovy”);
argsList.add(scriptPath.toabsolutionPath().toString());
Collections.addAll(argsList,args);
Process Process=Runtime.getRuntime().exec(argsList.toArray(新字符串[argsList.size()]);
//注:输出输入是过程的输出
字符串输入=Streams.asString(process.getInputStream());
字符串错误=Streams.asString(process.getErrorStream());
logger.info(“Groovy输出用于“+数组.toString(args)+”\r\n“+输入);
logger.info(“Groovy错误用于“+数组.toString(args)+”\r\n“+错误);
int returnValue=process.waitFor();
如果(返回值!=0){
抛出新的RuntimeException(“Groovy进程返回”+returnValue);
}
}捕获(可丢弃的e){
抛出新的RuntimeException(“运行构建脚本失败:“+scriptPath+”+Joiner.on(“”).join(args),e);
}
}

当然,问题是
groovy
不是一个可识别的命令。由于环境变量
PATH
以及cmd.exe的解析功能,它可以从命令行工作。在linux上,有一种不同的解析机制。为了将groovy可执行文件传递给
Runtime.exec()
,查找groovy可执行文件的平台无关方法是什么?

一种干净的方法是将可执行文件的绝对路径作为某种配置参数传递给应用程序

您也可以解析
PATH
环境变量并自行搜索,但是:

  • 不同的平台可以有不同的机制来搜索可执行文件。例如,他们使用不同的,你需要处理
  • 这是一种安全问题。攻击者可以向您的程序传递指向名为
    groovy
    的恶意程序的
    PATH
    环境变量

我建议采取不同的方法。您可以使用单独的类加载器来加载groovy脚本。优点:

  • 您还可以避免问题和碰撞问题
  • 但您不需要生成任何外部进程
  • 您还可以使用自定义脚本限制允许脚本执行的操作
  • 您可以更好地与脚本通信——使用方法调用,而不仅仅是stdin/out
  • 另见:


    您还可以将其与Java脚本API结合使用。这也许是最健壮、最灵活的解决方案。有关此信息,请参见


    我们实际上使用了另一个类加载器,但没有雪茄。我们所做的是在系统变量中定义groovy可执行文件的位置,并为Windows添加“cmd/c”:

    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);
            }
        }
    }
    
    import com.google.common.base.Joiner;
    导入org.apache.commons.lang.SystemUtils;
    导入org.apache.log4j.Logger;
    导入java.nio.file.Path;
    导入java.util.array;
    导入java.util.Collections;
    导入java.util.List;
    导入静态com.google.common.collect.Lists.newArrayList;
    导入静态org.apache.ivy.util.Checks.checkNotNull;
    公共类GroovyRunner{
    私有最终静态记录器Logger=LoggerHelper.getLogger();
    公共静态void runGroovyScript(路径scriptPath,字符串…args){
    试一试{
    List argsList=newArrayList();
    字符串groovyPath=System.getenv(“PLAY_GROOVY_PATH”);
    if(SystemUtils.IS\u OS\u WINDOWS){
    //窗口,没有简单的PLAY\u GROOVY\u路径默认值
    checkNotNull(groovyPath,“缺少环境变量‘PLAY_GROOVY_PATH’”);
    argsList.add(“cmd”);
    argsList.add(“/c”);
    argsList.add(groovyPath);
    }否则{
    if(groovyPath==null){
    //为linux提供合理的默认值
    groovyPath=“/usr/bin/groovy”;
    }
    argsList.add(groovyPath);
    }
    argsList.add(scriptPath.toabsolutionPath().toString());
    Collections.addAll(argsList,args);
    字符串join=Collections3.join(argsList,“”);
    ExecCommand process=新的ExecCommand(join);
    //注:输出输入是过程的输出
    字符串输出=process.getOutput();
    字符串错误=process.getError();
    logger.info(“Groovy输出用于“+数组.toString(args)+”\r\n“+输出);
    logger.info(“Groovy错误用于“+数组.toString(args)+”\r\n“+错误);
    if(process.getReturnValue()!=0){
    抛出新的RuntimeException(“Groovy进程返回”+process.getReturnValue());
    }
    }捕获(可丢弃的e){
    抛出新的RuntimeException(“运行groovy脚本失败:“+scriptPath+”+Joiner.on(“”).join(args),e);
    }
    }
    }
    
    允许远程执行沙盒代码。看看。

    我想这应该能回答你的问题:@SamuelAudet-我不确定它是否有。好吧,也许你不熟悉
    java.home
    系统属性,它包含
    bin
    目录下的
    java
    可执行文件?我们实际上使用了另一个类加载器,但没有雪茄。我们所做的是在系统变量中定义groovy可执行文件的位置,并为Windows添加“cmd/c”。我会把我们的密码贴出来作为答案。