Java Web Start应用程序中的ProcessBuilder进程行为不一致

时间:2013-06-21 15:07:41

标签: java macos java-web-start

尝试使用Java 1.7.0_21和_25在Mac OS X 10.8.4上运行的Java Web Start应用程序中使用ProcessBuilder执行特定命令时遇到了问题。

我使用ProcessBuilder执行“/ usr / sbin / system_profiler”命令以获取有关客户端计算机的一些信息(例如cpu名称,#processor等)。

启动Web时正确执行命令:

启动应用程序
  • 仅带URL参数的命令行javaws
  • 与Web Start-created application bundle
  • 具有相同参数的命令行javaws
  • Java Web Start系统首选项缓存应用程序对话框

通过以下方式启动时,命令正确执行:

  • 首次启动时由Web Start创建的Mac应用程序包的快捷方式

在使用Web Start快捷方式启动的情况下,“system_profiler”进程会创建一个子系统“system_profiler”,它会创建自己的子级,依此类推,直到 最终我收到以下错误(可能是在进程可用性耗尽时):

Failed to gather report from '/usr/sbin/system_profiler -xml SPHardwareDataType -detailLevel full', exception: couldn't fork: errno 35

注意:即使“/ usr / sbin / system_profiler”仅使用“SPHardwareDataType”参数启动,也会出现上述错误。

Activity Monitor showing created processes

这个问题似乎特定于“system_profiler”命令,因为它不会发生在其他命令的(通常很小的)随机采样中。

我还尝试了几种不同的方法来执行命令:

/usr/sbin/system_profiler
/usr/sbin/system_profiler SPHardwareDataType
/bin/sh -c /usr/sbin/system_profiler
/bin/sh -c /usr/sbin/system_profiler SPHardwareDataType
/bin/tcsh -c /usr/sbin/system_profiler 

所有组合都有相同的行为。

应用程序包Info.plist在“WebStartArgs”键下包含以下键值对:

 - Item 0: -localfile
 - Item 1: -online
 - Item 2: -J-Djnlp.application.href=http://localhost:8080/test/test.jnlp
 - Item 3: /Users/blah/Library/Application Support/Oracle/Java/Deployment/cache/6.0/40/744be8-7ce41b1a

如上所述,我尝试使用相同的参数通过命令行启动,但问题不会发生。

这是一个展示问题的精简测试应用程序:

import java.io.*;
import java.util.Arrays;

public class TestProcessBuilder {

    public static void main(String[] commands) throws IOException, InterruptedException {
        System.out.println("Args: " + Arrays.toString(commands));

        final ProcessBuilder pb = new ProcessBuilder(commands).redirectErrorStream(true);
        System.out.println("Environment: " + pb.environment());

        final Process p = pb.start();
        final StringBuilder buffer = new StringBuilder();

        Thread t = new Thread() {
            @Override
            public void run() {
                InputStream stdoutStream = null;
                try {
                    stdoutStream = new BufferedInputStream(p.getInputStream());
                    for(;;) {
                        int c = stdoutStream.read();
                        if(c == -1)
                            break;
                        buffer.append((char) c);
                    }
                    System.out.println("stdout buffer: " + buffer);
                } catch(IOException e) {
                    throw new RuntimeException(e);
                } finally {
                    close(stdoutStream);
                }                               
            }
        };

        t.start();

        int result = p.waitFor();
        t.join();
        if(result != 0) {
            throw new RuntimeException("Error result: " + result + " - " + buffer);
        }
    }

    private static void close(Closeable closeable) {
        try {
            if(closeable != null)
                closeable.close();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

作为一个注释,我也试过没有单独的线程来处理过程输出

以下是简单测试应用程序的JNLP文件:

<jnlp spec="1.0+" codebase="http://localhost:8080/test" href="test.jnlp">
  <information>
    <title>Test Process Builder</title>
    <vendor>Test Vendor</vendor>
    <homepage href="http://www.test.com" />
    <description>Launches Test Process Builder</description>
    <description kind="short">Test Process Builder</description>

    <shortcut online="true">
        <desktop />
    </shortcut>
  </information>

  <security>
    <all-permissions/>
  </security>

  <update check="always" policy="always"/>

  <resources>
    <java href="http://java.sun.com/products/autodl/j2se" version="1.7.0_21+"/>
    <property name="jnlp.versionEnabled" value="false"/>

    <jar href="lib/test.jar" download="eager" main="true"/>
  </resources>

  <application-desc main-class="netmedical.util.TestProcessBuilder">
      <argument>/bin/sh</argument>
      <argument>-c</argument>
      <argument>/usr/sbin/system_profiler SPHardwareDataType</argument>
  </application-desc>
</jnlp>

我也尝试过将JNLP转换为引用本地文件系统:

codebase="file://localhost/Library/Tomcat/webapps/test"

并发生相同的行为。

启动Mac应用程序包时,唯一的区别必须与运行时环境有关,但我不知道这可能是什么区别。

是否有问题:

  • 从Java应用程序启动进程的方式?
  • 处理输出的方式?
  • Web Start部署配置?
  • 其他?

0 个答案:

没有答案