1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 package helper;
28 
29 import java.io.BufferedReader;
30 import java.io.InputStream;
31 import java.io.File;
32 import java.io.PrintWriter;
33 import java.io.PrintStream;
34 import java.io.LineNumberReader;
35 import java.io.InputStreamReader;
36 import java.io.OutputStreamWriter;
37 import java.io.Writer;
38 import java.util.Calendar;
39 import java.util.Date;
40 import java.util.GregorianCalendar;
41 import lib.TestParameters;
42 import share.LogWriter;
43 import util.PropertyName;
44 import util.utils;
45 
46 /**
47  * Class collect information from input stream in
48  * background (sparate thread) and outputs it to
49  * some log stream. I helps to avoid buffer overflow
50  * when output stream has small buffer size (e.g.
51  * in case when handling stdout from external
52  * <code>Process</code>)
53  *
54  * This class is currently used by ProcesHandler
55  * internally only.
56  */
57 class Pump extends Thread
58 {
59 
60     private LineNumberReader reader;
61     private String pref;
62     private StringBuffer buf = new StringBuffer(256);
63     private PrintWriter log;
64     private boolean bOutput;
65 
66     /**
67      * Creates Pump for specified <code>InputStream</code>.
68      * This Pump also synchronously output text read to
69      * log by prefixed lines. Constructor immediately
70      * starts reading in a separate thread.
71      *
72      * @param is Stream which requires permanent reading.
73      * @param log Writer where prefixed text lines to be output
74      * @param outPrefix A prefix which is printed at the
75      *   beginning of each output line.
76      */
77     public Pump(InputStream is, PrintWriter log, String outPrefix, boolean _bOutput)
78     {
79         this.pref = (outPrefix == null) ? "" : outPrefix;
80         reader = new LineNumberReader(new InputStreamReader(is));
81         this.log = log;
82         this.bOutput = _bOutput;
83         start();
84     }
85 
86     public void run()
87     {
88         try
89         {
90             String line = reader.readLine();
91             while (line != null)
92             {
93                 if (bOutput)
94                 {
95                     log.println(pref + line);
96                     log.flush();
97                 }
98                 buf.append(line).append('\n');
99                 line = reader.readLine();
100             }
101         }
102         catch (java.io.IOException e)
103         {
104             log.println(pref + "Exception occured: " + e);
105         }
106     }
107 
108     /**
109      * Returns the text collected from input stream.
110      */
111     public String getStringBuffer()
112     {
113         return buf.toString();
114     }
115 }
116 
117 /**
118  * Class provides convenient way for running external program
119  * handle its standard streams, control execution and check results.
120  * Instance of this class must be created only for a single
121  * execution. If you need to execute the same command again you
122  * should create a new instance for this.
123  */
124 public class ProcessHandler
125 {
126 
127     private String cmdLine;
128     private String[] cmdLineArray;
129     private String[] envVars = null;
130     private File workDir = null;
131     private PrintWriter log;
132     private int exitValue = -1;
133     private boolean isFinished = false;
134     private boolean isStarted = false;
135     private boolean mbTimedOut = false;
136     private long mTimeOut = 0;
137     private String stdInBuff = "";
138     private Pump stdout = null;
139     private Pump stderr = null;
140     private PrintStream stdIn = null;
141     private Process m_aProcess = null;
142     private TestParameters param = null;
143     private boolean debug = false;
144     private boolean bUseOutput = true;
145 
146     private int m_nProcessTimeout = 0;
147     private String m_sProcessKiller;
148     private ProcessWatcher m_aWatcher;
149 
150     /**
151      * Creates instance with specified external command.
152      * Debug info and output
153      * of external command is printed to stdout.
154      * @param cmdLine
155      */
156     public ProcessHandler(String cmdLine)
157     {
158         this(cmdLine, null, null, null, 0);
159     }
160 
161     /**
162      * Creates instance with specified external command
163      * including parameters as an array.
164      * Debug info and output
165      * of external command is printed to stdout.
166      * @param cmdLines
167      */
168     public ProcessHandler(String[] cmdLines)
169     {
170         this(null, null, null, null, 0);
171         cmdLineArray = cmdLines;
172     }
173 
174     /**
175      * Creates instance with specified external command
176      * including parameters as an array, with environment
177      * variables.
178      * Debug info and output
179      * of external command is printed to stdout.
180      * @param cmdLines
181      * @param envVars
182      * @see java.lang.Runtime exec(String[], String[])
183      */
184     public ProcessHandler(String[] cmdLines, String[] envVars)
185     {
186         this(null, null, null, envVars, 0);
187         cmdLineArray = cmdLines;
188     }
189 
190     /**
191      * Creates instance with specified external command
192      * including parameters as an array, with environment
193      * variables. The command will be started in workDir.
194      * Debug info and output
195      * of external command is printed to stdout.
196      * @param cmdLines
197      * @param workDir
198      */
199     public ProcessHandler(String[] cmdLines, File workDir)
200     {
201         this(null, null, workDir, null, 0);
202         cmdLineArray = cmdLines;
203 
204     }
205 
206     /**
207      * Creates instance with specified external command and
208      * log stream where debug info and output
209      * of external command is printed out.  The command will be started in workDir.
210      * @param cmdLines
211      * @param log
212      * @param workDir
213      */
214     public ProcessHandler(String[] cmdLines, PrintWriter log, File workDir)
215     {
216         this(null, log, workDir, null, 0);
217         cmdLineArray = cmdLines;
218     }
219 
220     /**
221      * Creates instance with specified external command and
222      * log stream where debug info and output
223      * of external command is printed out.
224      * @param cmdLine
225      * @param log
226      */
227     public ProcessHandler(String cmdLine, PrintWriter log)
228     {
229         this(cmdLine, log, null, null, 0);
230     }
231 
232     /**
233      * Creates instance with specified external command and set the time out for the command.
234      * @param cmdLine
235      * @param timeOut
236      */
237     public ProcessHandler(String cmdLine, int timeOut)
238     {
239         this(cmdLine, null, null, null, timeOut);
240     }
241 
242     /**
243      * Creates instance with specified external command which
244      * will be executed in the some work directory.
245      * Debug info and output
246      * of external commandis printed to stdout.
247      * @param cmdLine
248      * @param workDir
249      */
250     public ProcessHandler(String cmdLine, File workDir)
251     {
252         this(cmdLine, null, workDir, null, 0);
253     }
254 
255     /**
256      * Creates instance with specified external command which
257      * will be executed in the some work directory.
258      * Debug info and output printed in log stream.
259      * @param cmdLine
260      * @param log
261      * @param workDir
262      */
263     public ProcessHandler(String cmdLine, PrintWriter log, File workDir)
264     {
265         this(cmdLine, log, workDir, null, 0);
266     }
267 
268     /**
269      * Creates instance with specified external command which
270      * will be executed in the some work directory  and
271      * log stream where debug info and output
272      * of external command is printed .
273      * The specified environment variables are set for the new process.
274      * If log stream is null, logging is printed to stdout.
275      * @param cmdLine
276      * @param log
277      * @param workDir
278      * @param envVars
279      */
280     public ProcessHandler(String cmdLine, PrintWriter log, File workDir, String[] envVars)
281     {
282         this(cmdLine, log, workDir, envVars, 0);
283     }
284 
285     /**
286      * Creates instance with specified external command which
287      * will be executed in the some work directory  and
288      *
289      * @param cmdLine       the command to be executed
290      * @param log           log stream where debug info and output
291      *                      of external command is printed .
292      * @param workDir       The working directory of the new process
293      * @param envVars       The specified environment variables are
294      *                      set for the new process.
295      *                      If log stream is null, logging is printed to stdout.
296      * @param  timeOut      When started sychronisly, the maximum time the
297      *                      process will live. When the process being destroyed
298      *                      a log will be written out. It can be asked on
299      *                      <code>isTimedOut()</code> if it has been terminated.
300      *
301      *                      timeOut > 0
302      *                      Waits specified time in miliSeconds for
303      *                      process to exit and return its status.
304      *
305      *                      timeOut = 0
306      *                      Waits for the process to end regulary
307      *
308      *                      timeOut < 0
309      *                      Kills the process immediately
310      *
311      *
312      */
313     public ProcessHandler(String cmdLine, PrintWriter log, File workDir, String[] envVars, long timeOut)
314     {
315         this.cmdLine = cmdLine;
316         this.workDir = workDir;
317         this.log = log;
318         this.cmdLine = cmdLine;
319         this.envVars = envVars;
320         if (log == null)
321         {
322             this.log = new PrintWriter(new OutputStreamWriter(System.out));
323         }
324         else
325         {
326             this.log = log;
327         }
328         this.mTimeOut = timeOut;
329     }
330 
331     /**
332      * Creates instance with specified external command which
333      * will be executed in the some work directory  and
334      * log stream where debug info and output of external command is printed.
335      * If log stream is null, logging is printed to stdout.
336      * From the <CODE>TestParameters</CODE> the <CODE>OfficeWachter</CODE> get a ping.
337      * @param commands
338      * @param log
339      * @param workDir
340      * @param shortWait If this parameter is ture the <CODE>mTimeOut</CODE> is set to 5000 ms, else it is set to
341      *        half of time out from parameter timeout.
342      * @param param the TestParameters
343      * @see lib.TestParameters
344      * @see helper.OfficeWatcher
345      */
346     public ProcessHandler(String[] commands, PrintWriter log, File workDir, int shortWait, TestParameters param)
347     {
348         this(null, log, workDir, null, 0);
349         this.cmdLineArray = commands;
350         this.param = param;
351         if (shortWait != 0)
352         {
353             this.mTimeOut = shortWait;
354         }
355         else
356         {
357             this.mTimeOut = (long) (param.getInt(PropertyName.TIME_OUT) / 1.3);
358         }
359         debug = param.getBool(PropertyName.DEBUG_IS_ACTIVE);
360 
361     }
362 
363     /**
364      * If not equal 0, the time to maximal wait.
365      * @param _n
366      */
367     public void setProcessTimeout(int _n)
368     {
369         m_nProcessTimeout = _n;
370     }
371 
372     /**
373      * This command will call after ProcessTimeout is arrived.
374      * @param _s
375      */
376     public void setProcessKiller(String _s)
377     {
378         m_sProcessKiller = _s;
379     }
380 
381     /**
382      * This method do an asynchronous execution of the commands. To avoid a interruption on long running processes
383      * caused by <CODE>OfficeWatcher</CODE>, the OfficeWatcher get frequently a ping.
384      * @see helper.OfficeWatcher
385      */
386     public void runCommand()
387     {
388 
389         boolean changedText = true;
390         int count = 0;
391         String memText = "";
392 
393         this.executeAsynchronously();
394 
395         OfficeWatcher ow = null;
396         if (param != null)
397         {
398             ow = (OfficeWatcher) param.get(PropertyName.OFFICE_WATCHER);
399         }
400         if (ow != null)
401         {
402             ow.ping();
403         }
404 
405         int hangcheck = 10;
406         while (!this.isFinished() && changedText)
407         {
408             count++;
409             // dbg("runCommand: waiting " + mTimeOut / 1000 + " seconds while command execution is ongoing... " + count);
410             // shortWait(mTimeOut);
411             // shortWait(2000); // wait 2 seconds.
412             //waitFor(mTimeOut);
413             waitFor(2000, false); // wait but don't kill
414 
415             if (ow != null)
416             {
417                 ow.ping();
418             }
419             // check for changes in the output stream. If there are no changes, the process maybe hangs
420             if (!this.isFinished())
421             {
422                 hangcheck--;
423                 if (hangcheck < 0)
424                 {
425                     String sOutputText = getOutputText();
426                     if (sOutputText.length() == memText.length())
427                     {
428                         changedText = false;
429                         // dbg("runCommand Could not detect changes in output stream!!!");
430                     }
431                     hangcheck = 10;
432                     memText = this.getOutputText();
433                 }
434             }
435         }
436 
437         if (!this.isFinished())
438         {
439             dbg("runCommand Process ist not finished but there are no changes in output stream.");
440             this.kill();
441         }
442     }
443 
444     public boolean isTimedOut()
445     {
446         return mbTimedOut;
447     }
448 
449     private void setTimedOut(boolean bTimedOut)
450     {
451         mbTimedOut = bTimedOut;
452     }
453 
454     /**
455      * Executes the command and returns only when the process
456      * exits.
457      *
458      * @return <code>true</code> if process was successfully
459      * started and correcly exits (exit code doesn't affect
460      * to this result).
461      */
462     public boolean executeSynchronously()
463     {
464         execute();
465         return waitFor(mTimeOut);
466     }
467 
468     /**
469      * Executes the command immediately returns. The process
470      * remains in running state. Control of its state should
471      * be made by <code>waitFor</code> methods.
472      *
473      * @return <code>true</code> if process was successfully
474      * started.
475      */
476     public boolean executeAsynchronously()
477     {
478         execute();
479         return isStarted();
480     }
481 
482     public synchronized void kill()
483     {
484         if (!isStarted())
485         {
486             return;
487         }
488         boolean exit = false;
489         int counter = 1;
490         while (counter < 3 && !exit)
491         {
492             m_aProcess.destroy();
493 
494             try
495             {
496                 Thread.sleep(1000 * counter); // 5000
497             }
498             catch (java.lang.InterruptedException e)
499             {
500             }
501             try
502             {
503                 final int exit_Value = m_aProcess.exitValue();
504                 if (exit_Value < 1)
505                 {
506                     exit = true;
507                 }
508                 else
509                 {
510                     counter++;
511                 }
512                 dbg("kill: process closed with exit code " + exit_Value);
513             }
514             catch (java.lang.IllegalThreadStateException e)
515             {
516                 if (counter < 3)
517                 {
518                     dbg("kill: Couldn't close process after " + counter + " attempts, trying again");
519                 }
520                 counter++;
521             }
522         }
523         isStarted = false;
524     }
525 
526     /**
527      * Returns the time in seconds since 1st January 1970
528      * @return
529      */
530     public static long getSystemTime()
531     {
532         // Calendar cal = new GregorianCalendar();
533         // final long nTime = cal.getTimeInMillis();
534         final long nTime = System.currentTimeMillis();
535         return nTime;
536     }
537     private long m_nExactStartTimeInMillisec;
538 
539     private void initialExactStartTime()
540     {
541         m_nExactStartTimeInMillisec = getSystemTime();
542     }
543 
544     public long getProcessStartTime()
545     {
546         return m_nExactStartTimeInMillisec;
547     }
548 
549     private void showEnvVars()
550     {
551         if (envVars != null)
552         {
553             for (int i = 0; i < envVars.length; i++)
554             {
555                 log.println("env: " + envVars[i]);
556             }
557         }
558         else
559         {
560             log.println("env: null");
561         }
562     }
563 
564     protected void execute()
565     {
566         if (isStarted())
567         {
568             throw new RuntimeException(
569                     "The process handler has already been executed.");
570         }
571         final Runtime runtime = Runtime.getRuntime();
572         try
573         {
574             if (cmdLine == null)
575             {
576                 log.println(utils.getDateTime() + "execute: Starting command from array: ");
577                 for (int i = 0; i < cmdLineArray.length; i++)
578                 {
579                     log.println(cmdLineArray[i]);
580                     // log.print(" ");
581                 }
582                 showEnvVars();
583                 log.println("");
584                 initialExactStartTime();
585                 initializeProcessKiller();
586                 m_aProcess = runtime.exec(cmdLineArray, envVars);
587             }
588             else
589             {
590                 if (workDir != null)
591                 {
592                     log.println(utils.getDateTime() + "execute: Starting command: ");
593                     log.println(cmdLine + " path=" + workDir.getAbsolutePath());
594                     showEnvVars();
595                     m_aProcess = runtime.exec(cmdLine, envVars, workDir);
596                 }
597                 else
598                 {
599                     log.println(utils.getDateTime() + "execute: Starting command: ");
600                     log.println(cmdLine);
601                     showEnvVars();
602                     m_aProcess = runtime.exec(cmdLine, envVars);
603                 }
604             }
605             isStarted = true;
606         }
607         catch (java.io.IOException e)
608         {
609             if (cmdLine == null)
610             {
611                 log.println(utils.getDateTime() + "execute: The command array can't be started: " + e);
612             }
613             else
614             {
615                 log.println(utils.getDateTime() + "execute: The command " + cmdLine + " can't be started: " + e);
616             }
617             return;
618         }
619         dbg("execute: pump io-streams");
620         stdout = new Pump(m_aProcess.getInputStream(), log, "out > ", bUseOutput);
621         stderr = new Pump(m_aProcess.getErrorStream(), log, "err > ", bUseOutput);
622         stdIn = new PrintStream(m_aProcess.getOutputStream());
623 
624         // int nExitValue = m_aProcess.exitValue();
625         // int dummy = 0;
626 
627         dbg("execute: flush io-streams");
628 
629         flushInput();
630     }
631 
632     /**
633      * This method is useful when the process was executed
634      * asynchronously. Waits for process to exit and return
635      * its result.
636      *
637      * @return <code>true</code> if process correctly exited
638      * (exit code doesn't affect to this result).
639      */
640     public boolean waitFor()
641     {
642         return waitFor(0);
643     }
644 
645     /**
646      * This method is useful when the process was executed
647      * asynchronously. Waits during specified time for process
648      * to exit and return its status.
649      *
650      * @param timeout      > 0
651      *                      Waits specified time in miliSeconds for
652      *                      process to exit and return its status.
653      *
654      *                      = 0
655      *                      Waits for the process to end regulary
656      *
657      *                      < 0
658      *                      Kills the process immediately
659      *
660      * @return <code>true</code> if process correctly exited
661      * (exit code doesn't affect to this result).
662      */
663     public boolean waitFor(long timeout)
664     {
665         return waitFor(timeout, true);
666     }
667 
668     private boolean waitFor(long timeout, boolean bKillProcessAfterTimeout)
669     {
670         if (isFinished())
671         {
672             return true;
673         }
674         if (!isStarted())
675         {
676             return false;
677         }
678 
679         if (timeout == 0)
680         {
681             try
682             {
683                 m_aProcess.waitFor();
684             }
685             catch (InterruptedException e)
686             {
687                 log.println("The process was interrupted: " + e);
688             }
689             isFinished = true;
690             try
691             {
692                 exitValue = m_aProcess.exitValue();
693             }
694             catch (IllegalThreadStateException e)
695             {
696             }
697         }
698         else
699         {
700             try
701             {
702                 while (!isFinished && timeout > 0)
703                 {
704                     isFinished = true;
705                     Thread.sleep(1000);
706                     timeout -= 1000;
707                     try
708                     {
709                         exitValue = m_aProcess.exitValue(); // throws exception if not finished
710                     }
711                     catch (IllegalThreadStateException e)
712                     {
713                         isFinished = false;
714                     }
715                 }
716                 if (timeout < 0)
717                 {
718                     setTimedOut(true);
719                     log.println("The process has timed out!");
720                 }
721             }
722             catch (InterruptedException ex)
723             {
724                 log.println("The process was interrupted: " + ex);
725             }
726         }
727 
728         if (bKillProcessAfterTimeout == true)
729         {
730             if (!isFinished)
731             {
732                 log.println("Going to destroy the process!!");
733                 m_aProcess.destroy();
734                 log.println("Process has been destroyed!");
735             }
736         }
737 //  Removed as hung up in SDK test 'PathSettings'
738 //        try {
739 //            stdout.join();
740 //            stderr.join();
741 //        } catch (InterruptedException e) {}
742 
743         return isFinished();
744     }
745 
746     protected void flushInput()
747     {
748         if (stdIn == null)
749         {
750             return;
751         }
752 
753         synchronized(stdInBuff)
754         {
755             stdIn.print(stdInBuff);
756             stdIn.flush();
757             stdInBuff = "";
758         }
759     }
760 
761     /**
762      * Returns the text output by external command to stdout.
763      * @return the text output by external command to stdout
764      */
765     public String getOutputText()
766     {
767         if (stdout == null)
768         {
769             return "";
770         }
771         else
772         {
773             return stdout.getStringBuffer();
774         }
775     }
776 
777     /**
778      * Returns the text output by external command to stderr.
779      * @return the text output by external command to stderr
780      */
781     public String getErrorText()
782     {
783         if (stderr == null)
784         {
785             return "";
786         }
787         else
788         {
789             return stderr.getStringBuffer();
790         }
791     }
792 
793     /**
794      * Prints the string specified to sdtin of external
795      * command. '\n' is not added so if you need you
796      * should terminate the string with '\n'. <p>
797      *
798      * The method can also be called before the command
799      * starts its execution. Then the text is buffered
800      * and transfered to command when it will be started.
801      * @param str
802      */
803     public void printInputText(String str)
804     {
805         stdInBuff += str;
806         flushInput();
807     }
808 
809     /**
810      * Returns information about was the command started or
811      * not.
812      *
813      * @return <code>true</code> if the external command was
814      * found and successfully started.
815      */
816     public boolean isStarted()
817     {
818         return isStarted;
819     }
820 
821     /**
822      * Returns the information about the final state of command
823      * execution.
824      *
825      * @return <code>true</code> if the command correctly starts,
826      * exits and was not interrupted due to timeout.
827      */
828     public boolean isFinished()
829     {
830         return isFinished;
831     }
832 
833     /**
834      * Returns exit code of the external command.
835      *
836      * @return exit code of command if it was finished,
837      * -1 if not.
838      */
839     public int getExitCode()
840     {
841         try
842         {
843             exitValue = m_aProcess.exitValue();
844         }
845         catch (Exception e)
846         {
847             //System.out.println("No ExitValue available");
848         }
849 
850         return exitValue;
851     }
852 
853     /** Causes the thread to sleep some time.
854      * @param milliseconds
855      */
856     public static void shortWait(long milliseconds)
857     {
858         try
859         {
860             Thread.sleep(milliseconds);
861         }
862         catch (InterruptedException e)
863         {
864             System.out.println("While waiting :" + e);
865         }
866     }
867 
868     private void dbg(String message)
869     {
870         if (debug)
871         {
872             log.println(utils.getDateTime() + "PH." + message);
873         }
874     }
875 
876     public void noOutput()
877     {
878         bUseOutput = false;
879     }
880     // -------------------------------------------------------------------------
881     class ProcessWatcher extends Thread
882     {
883 
884         private int m_nTimeoutInSec;
885         private String m_sProcessToStart;
886         private boolean m_bInterrupt;
887 
888         public ProcessWatcher(int _nTimeOut, String _sProcess)
889         {
890             m_nTimeoutInSec = _nTimeOut;
891             m_sProcessToStart = _sProcess;
892             m_bInterrupt = false;
893         }
894 
895         /**
896          * returns true, if the thread should hold on
897          * @return
898          */
899         public synchronized boolean isInHoldOn()
900         {
901             return m_bInterrupt;
902         }
903         /**
904          * Marks the thread to hold on, next time
905          * STUPID: The thread must poll this flag itself.
906          *
907          * Reason: interrupt() seems not to work as expected.
908          */
909         public synchronized void holdOn()
910         {
911             m_bInterrupt = true;
912             interrupt();
913         }
914 
915         public void run()
916         {
917             while (m_nTimeoutInSec > 0)
918             {
919                 m_nTimeoutInSec--;
920                 try
921                 {
922                     sleep(1000);
923                 }
924                 catch(java.lang.InterruptedException e)
925                 {
926                     // interrupt flag is set back to 'not interrupted' :-(
927                 }
928                 if (isInHoldOn())
929                 {
930                     break;
931                 }
932             }
933             if (m_nTimeoutInSec <= 0 && !isInHoldOn())       // not zero, so we are interrupted.
934             {
935                 system(m_sProcessToStart);
936             }
937         }
938 
939         /**
940          * Start an external Process
941          * @param _sProcess
942          */
943         private void system(String _sProcess)
944         {
945             if (_sProcess == null)
946             {
947                 return;
948             }
949 
950             try
951             {
952 
953                 // run a _sProcess command
954                 // using the Runtime exec method:
955                 Process p = Runtime.getRuntime().exec(_sProcess);
956 
957                 BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
958 
959                 BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
960 
961                 // read the output from the command
962                 String s;
963                 while ((s = stdInput.readLine()) != null)
964                 {
965                     System.out.println("out:" + s);
966                 }
967 
968                 // read any errors from the attempted command
969                 while ((s = stdError.readLine()) != null)
970                 {
971                     System.out.println("err:" + s);
972                 }
973 
974             }
975             catch (java.io.IOException e)
976             {
977                 System.out.println("exception caught: ");
978                 e.printStackTrace();
979             }
980 
981         }
982     }
983 
984     /**
985      *  If the timeout only given by setProcessTimeout(int seconds) function is != 0,
986      *  a extra thread is created and after time has run out, the ProcessKiller string
987      *  given by function setProcessKiller(string) will execute.
988      *  So it is possible to kill a running office after a given time of seconds.
989      */
990     private void initializeProcessKiller()
991     {
992         if (m_nProcessTimeout != 0)
993         {
994             m_aWatcher = new ProcessWatcher(m_nProcessTimeout, m_sProcessKiller);
995             m_aWatcher.start();
996         }
997     }
998 
999     /**
1000      * to stop the extra thread, before he will kill a running office. This will stop the thread.
1001      */
1002     public void stopWatcher()
1003     {
1004         if (m_aWatcher != null)
1005         {
1006             m_aWatcher.holdOn();
1007             shortWait(5000);
1008         }
1009     }
1010 }
1011