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