JDK-4738465 : (process) Need to create subprocess environment derived from current environment
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0,1.3.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2002-08-28
  • Updated: 2017-05-16
  • Resolved: 2003-09-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
5.0 tigerFixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description

Name: pa48320			Date: 08/28/2002


When we develop new feature of environment switching for Oracle Reports product, we look into jre's Runtime.exec(cmdline, envp) function to spawn a new process with a set of environment. We found once we put environment to envp, some functionality (such as orb.init()) in the sub-process stop working. We searched sun's bugdb and found related bug 4115037 and 4064912, and understood the reason of the failure. Although there is a workaround for the problem, but we think the workaround is against 100% pure java implementation for main process, because in java there is no way to get environment variable. We have to call jni into native function to get certain environment variables and add them to envp.

We (as well as from many comments in the bugdb) think it is highly desirable feature to have another flavor of Runtime.exec() which inherits the environment from main process plus new
environment specified by envp.

Following is the source code to demostrates the problem. Run it on Windows platform. If you run
java MainProc CreateOrb
it will succeed. If you run
java MainProc CreateOrb -e
it will fail because it clears the several important Windows environment variables.

1. MainProc.java - Main process:
import java.io.*;

public class MainProc
{
  static Process p;

  public static void main(String []args) throws IOException,
                                                InterruptedException
  {
    if (args.length == 0)
    {
      System.out.println("Usage: java MainProc <SubProcessClassName> [-e]");
      System.out.println("  <Default>   Spawns SubProc without environment");
      System.out.println("  -e          Spawns SubProc with environment");
      return;
    }

    Runtime rt = Runtime.getRuntime();

    String cmdLine = "javaw -cp . " + args[0];

    /*
     * Spawn the process with environment setting
     */
    if (args.length >= 2 && args[1].equalsIgnoreCase("-e"))
    {
      String[] envp = new String[1];
      envp[0] = "Foo=Bar";

      p = rt.exec(cmdLine, envp);
    }
    /*
     * Spawn the process without environment setting
     */
    else
    {
      p = rt.exec(cmdLine);
    }

    /*
     * Catch the process in action
     */
    StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");
    StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "OUTPUT");
    errorGobbler.start();
    outputGobbler.start();

    int rv = p.waitFor();

    System.out.println("Return value: "+rv);
  }

}

class StreamGobbler extends Thread
{
  InputStream is;
  String type;

  StreamGobbler(InputStream is, String type)
  {
      this.is = is;
      this.type = type;
  }

  public void run()
  {
    try
    {
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      String line=null;
      while ((line = br.readLine()) != null)
        System.out.println(type+">"+line);
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
}

2. CreateOrb.java - Sub process:
public class CreateOrb
{
  public static void main(String []args)
  {
    try
    {
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);

      if (orb != null)
        System.out.println("Successfully created an ORB object");
      else
        System.out.println("orb is null");
      System.exit(0);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      System.exit(-1);
    }
  }
}
(Review ID: 163687) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b20
14-06-2004

WORK AROUND Name: pa48320 Date: 08/28/2002 Use jni to retrieve the surrounding environment and append to envp. ======================================================================
11-06-2004

EVALUATION A non-jni workaround would be possible if we could get the parent process' environment. See bug 4642629. In that case, we could get the environment, modify it, and use the existing Runtime APIs. -- iag@sfbay 2002-08-28 An even cleaner solution to this problem would be to define two new methods: A new System.getenv() method that returns a Map<String,String> of the environment variables of the JRE process, and a new Runtime.exec method that takes a command and an environment-variable map. -- ###@###.### 2003/1/31 The smallest change to the API that would satisfy the user's desires is the addition of Map<String,String> System.environment() and then adding Process Runtime.exec(String[]args,Map<String,String>environ, File dir) The obvious problem is that Runtime.exec is already horribly overloaded, with four methods that take a String envp[] style environment. public Process exec(String cmd, String envp[]) public Process exec(String command, String envp[], File dir) public Process exec(String cmdarray[], String envp[]) public Process exec(String cmdarray[], String envp[], File dir) If we were to be consistent, we would add 4 new methods that mirror the above. The situation will get worse in the very likely event that we will want to add new attributes that new processes can have, for example: - redirect stdio streams - change process priority - create daemon processes - provide byte-level access to process properties like working directory. An example of what I fear is the huge list of parameters to the Windows CreateProcess function. A better way is to have a separate class to capture nascent process attributes. class ProcessBuilder { public ProcessBuilder(String command...) public Map<String,String> environment() public void setWorkingDirectory(File dir) } Unix folks can can think of this class as the state of a process after fork() and before exec(). An advantage of this design is that the map returned by environment() can be designed in such a way that the exact byte sequences of environment variables not modified by the user program will be perfectly preserved in any child process. There should be no setEnvironment(Map<String,String>) method. While implementing class ProcessBuilder, we also added a method ProcessBuilder.redirectErrorStream() which addresses the functionality described in this rfe: 4480528: (process) Need combined stderr/stdout streams ###@###.### 2003-08-03
03-08-2003