0

I am using the following code to run terminal commands through my command prompt

String[] command =
        {
      "zsh"
          };
                Process p = Runtime.getRuntime().exec(command);
                new Thread(new SyncPipe(p.getErrorStream(), b)).start();
                new Thread(new SyncPipe(p.getInputStream(), b)).start();
                PrintWriter stdin = new PrintWriter(p.getOutputStream());
                stdin.println("source ./taxenv/bin/activate");
                stdin.println("python runner.py");
                stdin.close();
                int returnCode = 0;
                try {
                    returnCode = p.waitFor();

                    String path2 = b + "/logs.txt"; // I am getting b value passed in from gc.jsp
                    if(new File(path2).exists())
                    {
                        BufferedReader reader = new BufferedReader(new FileReader(path2));

                            while ((line1 = reader.readLine()) != null) 
                                {
                                    content= content + line1 +"<br>";
                                }
                            reader.close();
                            request.setAttribute("logs", content);

                            RequestDispatcher rd = request.getRequestDispatcher("gc.jsp");
                            rd.forward(request, response);


                }
                }
                catch (InterruptedException e) {
                    e.printStackTrace();

                }
                    System.out.println("Return code = " + returnCode +b);
    }               
    class SyncPipe implements Runnable
    {

    public SyncPipe(InputStream istrm, String c) {
          istrm_ = istrm;
          b_ = c;
      }

    @SuppressWarnings("unused")
    public void run() {
          try
          {
              final byte[] buffer = new byte[1024];
            for(int length = 0; (length = istrm_.read(buffer)) != -1; )
              {
                   str = str + IOUtils.toString(istrm_, "UTF-8") + b_;
              }
            System.out.println(str);

            String location = b_ + "/" + "logs.txt";
            File file = new File(location);
            if(!file.exists())
            {
                file.createNewFile();
            }
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(str);
            bw.close();


          }

          catch (Exception e)
          {
              e.printStackTrace();
          }
      }
      private final InputStream istrm_;
      private final String b_;

When I run this code I expect it to be re directed to gc.jsp, but it displays as follows

enter image description here

Now, When I refresh the above page I am getting output as expected, shown below.

enter image description here

Why is this happening and how do I solve this?

=============================EDIT==========================

I've added

bw.close() //Closing bufferedwriter
fw.close() //Closing file writer

still of no use.

Now, I've added

TimeUnit.SECONDS.sleep(5);

This works fine for small files, so basically the problem is that code from the line

String path2 = b + "/logs.txt";

must wait for the process p to complete.

How do I do this?

  • Are exceptions preventing the forward? – Bart Mar 21 '14 at 05:01
  • I have no idea..when I refresh page I am getting the output –  Mar 21 '14 at 05:03
  • The console log is also empty..I guess there is some logical error I need to process the if loop only after the completion of returnCode = p.waitFor(); but how do I do it? –  Mar 21 '14 at 05:04
  • 3
    http://stackoverflow.com/questions/5483830/process-waitfor-never-returns – ray Mar 24 '14 at 05:19
  • Try While(p.waitFor() == 0) {} – ray Mar 24 '14 at 05:27
  • @ray I've tried p.waitfor() == 0, it doesn't work. –  Mar 24 '14 at 06:23
  • You're launching a zsh process and sending it two commands to run. Don't you need to send it an `exit` command (or ^D) to get it to exit? (BTW, the docs on Process recommend buffering its I/O streams.) – Jerry101 Mar 24 '14 at 06:35
  • Yes, I did exit it. But I've not included those lines here as it is of not much importance here. –  Mar 24 '14 at 06:48
  • As i see it, you try to read the logs.txt file before the SyncPipe wrote the file. You can solve this with a barrier. – Absurd-Mind Mar 25 '14 at 13:39
  • Yes, that is my problem..what barrier? –  Mar 25 '14 at 13:39

1 Answers1

1

Your problem is that you try reading the files before your SyncPipes finished writing to your files. You can solve this by waiting until all threads are finished (join())

Process p = Runtime.getRuntime().exec(command);
Thread threadError = new Thread(new SyncPipe(p.getErrorStream(), b));
Thread threadInput = new Thread(new SyncPipe(p.getInputStream(), b));

threadError.start();
threadInput.start();

/* writing to process */

// wait until your process finished
p.waitFor();

// wait for both threads until they finished writing to files
threadError.join();
threadInput.join();

// read your files

Description: Your SyncPipe thread will stop when the Input/ErrorStream is closed because the process p stopped. Then it will write everything to file and close the files appropriately. After that the Thread is stopped correctly.

The join method tells your main thread (the caller of join) to wait until the thread is stopped (the callee of join, e.g. threadError). waitFor is somewhat equivalent to join.

After that you can say for sure that all threads are stopped correctly (p, threadError and threadInput) and therefore all files are written to disk. Now you can read them.

Absurd-Mind
  • 7,884
  • 5
  • 35
  • 47