2

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

4

3 回答 3

1

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

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

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

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

  1. 您还将避免 JAR 碰撞问题。
  2. 但是您不需要产生任何外部进程。
  3. 您还可以使用自定义SecurityManager限制允许脚本执行的操作。
  4. 您可以更好地与脚本通信 - 使用方法调用而不是标准输入/输出。

也可以看看:


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

于 2012-08-28T12:38:56.473 回答
1

java-sandbox允许远程执行沙盒代码。看看http://blog.datenwerke.net/2013/06/sandboxing-groovy-with-java-sandbox.html

于 2013-06-14T13:43:56.003 回答
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);
        }
    }
}
于 2012-08-29T07:00:38.260 回答