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

时间:2012-08-28 11:26:02

标签: java groovy process

我正在尝试从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);
    }
}

问题当然是groovy不是公认的命令。由于PATH环境变量以及cmd.exe所做的解析,它可以在命令行中运行。在linux上,有一种不同的解析机制。什么是与平台无关的方法来查找groovy可执行文件,以便将其传递给Runtime.exec()

3 个答案:

答案 0 :(得分:1)

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

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

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

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

  1. 您也可以避免JAR碰撞问题。
  2. 但您不需要生成任何外部进程。
  3. 您还可以使用自定义SecurityManager限制允许脚本执行的操作。
  4. 您可以更好地与脚本进行通信 - 使用方法调用而不仅仅是stdin / out。
  5. 另见:


    您也可以将它与Java Scripting API结合使用。这可能是最强大和最灵活的解决方案。为此,请参阅

答案 1 :(得分:1)

答案 2 :(得分:0)

我们实际上摆弄了另一个类装载机,但没有雪茄。我们所做的是在系统变量中定义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);
        }
    }
}