KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > Redirector


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18 package org.apache.tools.ant.taskdefs;
19
20 import java.io.File JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.PrintStream JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.io.StringReader JavaDoc;
27 import java.io.BufferedReader JavaDoc;
28 import java.io.InputStreamReader JavaDoc;
29 import java.io.PipedOutputStream JavaDoc;
30 import java.io.ByteArrayInputStream JavaDoc;
31 import java.io.ByteArrayOutputStream JavaDoc;
32 import java.util.Arrays JavaDoc;
33 import java.util.Vector JavaDoc;
34
35 import org.apache.tools.ant.Project;
36 import org.apache.tools.ant.ProjectComponent;
37 import org.apache.tools.ant.Task;
38 import org.apache.tools.ant.BuildException;
39 import org.apache.tools.ant.filters.util.ChainReaderHelper;
40 import org.apache.tools.ant.util.StringUtils;
41 import org.apache.tools.ant.util.TeeOutputStream;
42 import org.apache.tools.ant.util.ReaderInputStream;
43 import org.apache.tools.ant.util.LeadPipeInputStream;
44 import org.apache.tools.ant.util.LazyFileOutputStream;
45 import org.apache.tools.ant.util.OutputStreamFunneler;
46 import org.apache.tools.ant.util.ConcatFileInputStream;
47 import org.apache.tools.ant.util.KeepAliveOutputStream;
48
49 /**
50  * The Redirector class manages the setup and connection of
51  * input and output redirection for an Ant project component.
52  *
53  * @since Ant 1.6
54  */

55 public class Redirector {
56
57     private static final String JavaDoc DEFAULT_ENCODING
58         = System.getProperty("file.encoding");
59
60     private class PropertyOutputStream extends ByteArrayOutputStream JavaDoc {
61         private String JavaDoc property;
62         private boolean closed = false;
63
64         PropertyOutputStream(String JavaDoc property) {
65             super();
66             this.property = property;
67         }
68
69         public void close() throws IOException JavaDoc {
70             if (!closed && !(append && appendProperties)) {
71                 setPropertyFromBAOS(this, property);
72                 closed = true;
73             }
74         }
75     }
76
77     /**
78      * The file(s) from which standard input is being taken.
79      * If > 1, files' content will be concatenated in the order received.
80      */

81     private File JavaDoc[] input;
82
83     /**
84      * The file(s) receiving standard output. Will also receive standard error
85      * unless standard error is redirected or logError is true.
86      */

87     private File JavaDoc[] out;
88
89     /**
90      * The file(s) to which standard error is being redirected
91      */

92     private File JavaDoc[] error;
93
94     /**
95       * Indicates if standard error should be logged to Ant's log system
96       * rather than the output. This has no effect if standard error is
97       * redirected to a file or property.
98       */

99     private boolean logError = false;
100
101     /**
102      * Buffer used to capture output for storage into a property
103      */

104     private PropertyOutputStream baos = null;
105
106     /**
107      * Buffer used to capture error output for storage into a property
108      */

109     private PropertyOutputStream errorBaos = null;
110
111     /** The name of the property into which output is to be stored */
112     private String JavaDoc outputProperty;
113
114     /** The name of the property into which error output is to be stored */
115     private String JavaDoc errorProperty;
116
117     /** String from which input is taken */
118     private String JavaDoc inputString;
119
120     /** Flag which indicates if error and output files are to be appended. */
121     private boolean append = false;
122
123     /** Flag which indicates that output should be always sent to the log */
124     private boolean alwaysLog = false;
125
126     /** Flag which indicates whether files should be created even when empty. */
127     private boolean createEmptyFiles = true;
128
129     /** The task for which this redirector is working */
130     private ProjectComponent managingTask;
131
132     /** The stream for output data */
133     private OutputStream JavaDoc outputStream = null;
134
135     /** The stream for error output */
136     private OutputStream JavaDoc errorStream = null;
137
138     /** The stream for input */
139     private InputStream JavaDoc inputStream = null;
140
141     /** Stream which is used for line oriented output */
142     private PrintStream JavaDoc outPrintStream = null;
143
144     /** Stream which is used for line oriented error output */
145     private PrintStream JavaDoc errorPrintStream = null;
146
147     /** The output filter chains */
148     private Vector JavaDoc outputFilterChains;
149
150     /** The error filter chains */
151     private Vector JavaDoc errorFilterChains;
152
153     /** The input filter chains */
154     private Vector JavaDoc inputFilterChains;
155
156     /** The output encoding */
157     private String JavaDoc outputEncoding = DEFAULT_ENCODING;
158
159     /** The error encoding */
160     private String JavaDoc errorEncoding = DEFAULT_ENCODING;
161
162     /** The input encoding */
163     private String JavaDoc inputEncoding = DEFAULT_ENCODING;
164
165     /** Whether to complete properties settings **/
166     private boolean appendProperties = true;
167
168     /** The thread group used for starting <code>StreamPumper</code> threads */
169     private ThreadGroup JavaDoc threadGroup = new ThreadGroup JavaDoc("redirector");
170
171     /** whether to log the inputstring */
172     private boolean logInputString = true;
173
174     /**
175      * Create a redirector instance for the given task
176      *
177      * @param managingTask the task for which the redirector is to work
178      */

179     public Redirector(Task managingTask) {
180         this((ProjectComponent) managingTask);
181     }
182
183     /**
184      * Create a redirector instance for the given task
185      *
186      * @param managingTask the project component for which the
187      * redirector is to work
188      * @since Ant 1.6.3
189      */

190     public Redirector(ProjectComponent managingTask) {
191         this.managingTask = managingTask;
192     }
193
194     /**
195      * Set the input to use for the task
196      *
197      * @param input the file from which input is read.
198      */

199     public void setInput(File JavaDoc input) {
200         setInput((input == null) ? null : new File JavaDoc[] {input});
201     }
202
203     /**
204      * Set the input to use for the task
205      *
206      * @param input the files from which input is read.
207      */

208     public synchronized void setInput(File JavaDoc[] input) {
209         this.input = input;
210     }
211
212     /**
213      * Set the string to use as input
214      *
215      * @param inputString the string which is used as the input source
216      */

217     public synchronized void setInputString(String JavaDoc inputString) {
218         this.inputString = inputString;
219     }
220
221     /**
222      * Set whether to include the value of the input string in log messages.
223      * Defaults to true.
224      * @param logInputString true or false.
225      * @since Ant 1.7
226      */

227     public void setLogInputString(boolean logInputString) {
228         this.logInputString = logInputString;
229     }
230
231     /**
232      * Set a stream to use as input.
233      *
234      * @param inputStream the stream from which input will be read
235      * @since Ant 1.6.3
236      */

237     /*public*/ void setInputStream(InputStream JavaDoc inputStream) {
238         this.inputStream = inputStream;
239     }
240
241     /**
242      * File the output of the process is redirected to. If error is not
243      * redirected, it too will appear in the output
244      *
245      * @param out the file to which output stream is written
246      */

247     public void setOutput(File JavaDoc out) {
248         setOutput((out == null) ? null : new File JavaDoc[] {out});
249     }
250
251     /**
252      * Files the output of the process is redirected to. If error is not
253      * redirected, it too will appear in the output
254      *
255      * @param out the files to which output stream is written
256      */

257     public synchronized void setOutput(File JavaDoc[] out) {
258         this.out = out;
259     }
260
261     /**
262      * Set the output encoding.
263      *
264      * @param outputEncoding <code>String</code>.
265      */

266     public synchronized void setOutputEncoding(String JavaDoc outputEncoding) {
267         if (outputEncoding == null) {
268             throw new IllegalArgumentException JavaDoc(
269                 "outputEncoding must not be null");
270         } else {
271             this.outputEncoding = outputEncoding;
272         }
273     }
274
275     /**
276      * Set the error encoding.
277      *
278      * @param errorEncoding <code>String</code>.
279      */

280     public synchronized void setErrorEncoding(String JavaDoc errorEncoding) {
281         if (errorEncoding == null) {
282             throw new IllegalArgumentException JavaDoc(
283                 "errorEncoding must not be null");
284         } else {
285             this.errorEncoding = errorEncoding;
286         }
287     }
288
289     /**
290      * Set the input encoding.
291      *
292      * @param inputEncoding <code>String</code>.
293      */

294     public synchronized void setInputEncoding(String JavaDoc inputEncoding) {
295         if (inputEncoding == null) {
296             throw new IllegalArgumentException JavaDoc(
297                 "inputEncoding must not be null");
298         } else {
299             this.inputEncoding = inputEncoding;
300         }
301     }
302
303     /**
304      * Controls whether error output of exec is logged. This is only useful
305      * when output is being redirected and error output is desired in the
306      * Ant log
307      *
308      * @param logError if true the standard error is sent to the Ant log system
309      * and not sent to output.
310      */

311     public synchronized void setLogError(boolean logError) {
312         this.logError = logError;
313     }
314
315     /**
316      * This <code>Redirector</code>'s subordinate
317      * <code>PropertyOutputStream</code>s will not set their respective
318      * properties <code>while (appendProperties && append)</code>.
319      *
320      * @param appendProperties whether to append properties.
321      */

322     public synchronized void setAppendProperties(boolean appendProperties) {
323         this.appendProperties = appendProperties;
324     }
325
326     /**
327      * Set the file to which standard error is to be redirected.
328      *
329      * @param error the file to which error is to be written
330      */

331     public void setError(File JavaDoc error) {
332         setError((error == null) ? null : new File JavaDoc[] {error});
333     }
334
335     /**
336      * Set the files to which standard error is to be redirected.
337      *
338      * @param error the file to which error is to be written
339      */

340     public synchronized void setError(File JavaDoc[] error) {
341         this.error = error;
342     }
343
344     /**
345      * Property name whose value should be set to the output of
346      * the process.
347      *
348      * @param outputProperty the name of the property to be set with the
349      * task's output.
350      */

351     public synchronized void setOutputProperty(String JavaDoc outputProperty) {
352         if (outputProperty == null
353          || !(outputProperty.equals(this.outputProperty))) {
354             this.outputProperty = outputProperty;
355             baos = null;
356         }
357     }
358
359     /**
360      * Whether output should be appended to or overwrite an existing file.
361      * Defaults to false.
362      *
363      * @param append if true output and error streams are appended to their
364      * respective files, if specified.
365      */

366     public synchronized void setAppend(boolean append) {
367         this.append = append;
368     }
369
370     /**
371      * If true, (error and non-error) output will be "teed", redirected
372      * as specified while being sent to Ant's logging mechanism as if no
373      * redirection had taken place. Defaults to false.
374      * @param alwaysLog <code>boolean</code>
375      * @since Ant 1.6.3
376      */

377     public synchronized void setAlwaysLog(boolean alwaysLog) {
378         this.alwaysLog = alwaysLog;
379     }
380
381     /**
382      * Whether output and error files should be created even when empty.
383      * Defaults to true.
384      * @param createEmptyFiles <code>boolean</code>.
385      */

386     public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) {
387         this.createEmptyFiles = createEmptyFiles;
388     }
389
390     /**
391      * Property name whose value should be set to the error of
392      * the process.
393      *
394      * @param errorProperty the name of the property to be set
395      * with the error output.
396      */

397     public synchronized void setErrorProperty(String JavaDoc errorProperty) {
398         if (errorProperty == null
399          || !(errorProperty.equals(this.errorProperty))) {
400             this.errorProperty = errorProperty;
401             errorBaos = null;
402         }
403     }
404
405     /**
406      * Set the input <code>FilterChain</code>s.
407      *
408      * @param inputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
409      */

410     public synchronized void setInputFilterChains(Vector JavaDoc inputFilterChains) {
411         this.inputFilterChains = inputFilterChains;
412     }
413
414     /**
415      * Set the output <code>FilterChain</code>s.
416      *
417      * @param outputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
418      */

419     public synchronized void setOutputFilterChains(Vector JavaDoc outputFilterChains) {
420         this.outputFilterChains = outputFilterChains;
421     }
422
423     /**
424      * Set the error <code>FilterChain</code>s.
425      *
426      * @param errorFilterChains <code>Vector</code> containing <code>FilterChain</code>.
427      */

428     public synchronized void setErrorFilterChains(Vector JavaDoc errorFilterChains) {
429         this.errorFilterChains = errorFilterChains;
430     }
431
432     /**
433      * Set a property from a ByteArrayOutputStream
434      *
435      * @param baos contains the property value.
436      * @param propertyName the property name.
437      *
438      * @exception IOException if the value cannot be read form the stream.
439      */

440     private void setPropertyFromBAOS(ByteArrayOutputStream JavaDoc baos,
441                                      String JavaDoc propertyName) throws IOException JavaDoc {
442
443         BufferedReader JavaDoc in
444             = new BufferedReader JavaDoc(new StringReader JavaDoc(Execute.toString(baos)));
445         String JavaDoc line = null;
446         StringBuffer JavaDoc val = new StringBuffer JavaDoc();
447         while ((line = in.readLine()) != null) {
448             if (val.length() != 0) {
449                 val.append(StringUtils.LINE_SEP);
450             }
451             val.append(line);
452         }
453         managingTask.getProject().setNewProperty(propertyName, val.toString());
454     }
455
456     /**
457      * Create the input, error and output streams based on the
458      * configuration options.
459      */

460     public synchronized void createStreams() {
461         if (out != null && out.length > 0) {
462             String JavaDoc logHead = new StringBuffer JavaDoc("Output ").append(
463                 ((append) ? "appended" : "redirected")).append(
464                 " to ").toString();
465             outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE);
466         }
467         if (outputProperty != null) {
468             if (baos == null) {
469                 baos = new PropertyOutputStream(outputProperty);
470                 managingTask.log("Output redirected to property: "
471                     + outputProperty, Project.MSG_VERBOSE);
472             }
473             //shield it from being closed by a filtering StreamPumper
474
OutputStream JavaDoc keepAliveOutput = new KeepAliveOutputStream(baos);
475             outputStream = (outputStream == null) ? keepAliveOutput
476                 : new TeeOutputStream(outputStream, keepAliveOutput);
477         } else {
478             baos = null;
479         }
480
481         if (error != null && error.length > 0) {
482             String JavaDoc logHead = new StringBuffer JavaDoc("Error ").append(
483                 ((append) ? "appended" : "redirected")).append(
484                 " to ").toString();
485             errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE);
486         } else if (!(logError || outputStream == null)) {
487             long funnelTimeout = 0L;
488             OutputStreamFunneler funneler
489                 = new OutputStreamFunneler(outputStream, funnelTimeout);
490             try {
491                 outputStream = funneler.getFunnelInstance();
492                 errorStream = funneler.getFunnelInstance();
493             } catch (IOException JavaDoc eyeOhEx) {
494                 throw new BuildException(
495                     "error splitting output/error streams", eyeOhEx);
496             }
497         }
498         if (errorProperty != null) {
499             if (errorBaos == null) {
500                 errorBaos = new PropertyOutputStream(errorProperty);
501                 managingTask.log("Error redirected to property: " + errorProperty,
502                     Project.MSG_VERBOSE);
503             }
504             //shield it from being closed by a filtering StreamPumper
505
OutputStream JavaDoc keepAliveError = new KeepAliveOutputStream(errorBaos);
506             errorStream = (error == null || error.length == 0) ? keepAliveError
507                 : new TeeOutputStream(errorStream, keepAliveError);
508         } else {
509             errorBaos = null;
510         }
511         if (alwaysLog || outputStream == null) {
512             OutputStream JavaDoc outputLog
513                 = new LogOutputStream(managingTask, Project.MSG_INFO);
514             outputStream = (outputStream == null)
515                 ? outputLog : new TeeOutputStream(outputLog, outputStream);
516         }
517         if (alwaysLog || errorStream == null) {
518             OutputStream JavaDoc errorLog
519                 = new LogOutputStream(managingTask, Project.MSG_WARN);
520             errorStream = (errorStream == null)
521                 ? errorLog : new TeeOutputStream(errorLog, errorStream);
522         }
523         if ((outputFilterChains != null && outputFilterChains.size() > 0)
524             || !(outputEncoding.equalsIgnoreCase(inputEncoding))) {
525             try {
526                 LeadPipeInputStream snk = new LeadPipeInputStream();
527                 snk.setManagingComponent(managingTask);
528
529                 InputStream JavaDoc outPumpIn = snk;
530
531                 Reader JavaDoc reader = new InputStreamReader JavaDoc(outPumpIn, inputEncoding);
532
533                 if (outputFilterChains != null && outputFilterChains.size() > 0) {
534                     ChainReaderHelper helper = new ChainReaderHelper();
535                     helper.setProject(managingTask.getProject());
536                     helper.setPrimaryReader(reader);
537                     helper.setFilterChains(outputFilterChains);
538                     reader = helper.getAssembledReader();
539                 }
540                 outPumpIn = new ReaderInputStream(reader, outputEncoding);
541
542                 Thread JavaDoc t = new Thread JavaDoc(threadGroup, new StreamPumper(
543                     outPumpIn, outputStream, true), "output pumper");
544                 t.setPriority(Thread.MAX_PRIORITY);
545                 outputStream = new PipedOutputStream JavaDoc(snk);
546                 t.start();
547             } catch (IOException JavaDoc eyeOhEx) {
548                 throw new BuildException(
549                     "error setting up output stream", eyeOhEx);
550             }
551         }
552
553         if ((errorFilterChains != null && errorFilterChains.size() > 0)
554             || !(errorEncoding.equalsIgnoreCase(inputEncoding))) {
555             try {
556                 LeadPipeInputStream snk = new LeadPipeInputStream();
557                 snk.setManagingComponent(managingTask);
558
559                 InputStream JavaDoc errPumpIn = snk;
560
561                 Reader JavaDoc reader = new InputStreamReader JavaDoc(errPumpIn, inputEncoding);
562
563                 if (errorFilterChains != null && errorFilterChains.size() > 0) {
564                     ChainReaderHelper helper = new ChainReaderHelper();
565                     helper.setProject(managingTask.getProject());
566                     helper.setPrimaryReader(reader);
567                     helper.setFilterChains(errorFilterChains);
568                     reader = helper.getAssembledReader();
569                 }
570                 errPumpIn = new ReaderInputStream(reader, errorEncoding);
571
572                 Thread JavaDoc t = new Thread JavaDoc(threadGroup, new StreamPumper(
573                     errPumpIn, errorStream, true), "error pumper");
574                 t.setPriority(Thread.MAX_PRIORITY);
575                 errorStream = new PipedOutputStream JavaDoc(snk);
576                 t.start();
577             } catch (IOException JavaDoc eyeOhEx) {
578                 throw new BuildException(
579                     "error setting up error stream", eyeOhEx);
580             }
581         }
582
583         // if input files are specified, inputString and inputStream are ignored;
584
// classes that work with redirector attributes can enforce
585
// whatever warnings are needed
586
if (input != null && input.length > 0) {
587             managingTask.log("Redirecting input from file"
588                 + ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE);
589             try {
590                 inputStream = new ConcatFileInputStream(input);
591             } catch (IOException JavaDoc eyeOhEx) {
592                 throw new BuildException(eyeOhEx);
593             }
594             ((ConcatFileInputStream) inputStream).setManagingComponent(managingTask);
595         } else if (inputString != null) {
596             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Using input ");
597             if (logInputString) {
598                 buf.append('"').append(inputString).append('"');
599             } else {
600                 buf.append("string");
601             }
602             managingTask.log(buf.toString(), Project.MSG_VERBOSE);
603             inputStream = new ByteArrayInputStream JavaDoc(inputString.getBytes());
604         }
605
606         if (inputStream != null
607             && inputFilterChains != null && inputFilterChains.size() > 0) {
608             ChainReaderHelper helper = new ChainReaderHelper();
609             helper.setProject(managingTask.getProject());
610             try {
611                 helper.setPrimaryReader(
612                     new InputStreamReader JavaDoc(inputStream, inputEncoding));
613             } catch (IOException JavaDoc eyeOhEx) {
614                 throw new BuildException(
615                     "error setting up input stream", eyeOhEx);
616             }
617             helper.setFilterChains(inputFilterChains);
618             inputStream = new ReaderInputStream(
619                 helper.getAssembledReader(), inputEncoding);
620         }
621     }
622
623     /**
624      * Create the StreamHandler to use with our Execute instance.
625      *
626      * @return the execute stream handler to manage the input, output and
627      * error streams.
628      *
629      * @throws BuildException if the execute stream handler cannot be created.
630      */

631     public synchronized ExecuteStreamHandler createHandler()
632         throws BuildException {
633         createStreams();
634         return new PumpStreamHandler(outputStream, errorStream, inputStream);
635     }
636
637     /**
638      * Pass output sent to System.out to specified output.
639      *
640      * @param output the data to be output
641      */

642     protected synchronized void handleOutput(String JavaDoc output) {
643         if (outPrintStream == null) {
644             outPrintStream = new PrintStream JavaDoc(outputStream);
645         }
646         outPrintStream.print(output);
647     }
648
649     /**
650      * Handle an input request
651      *
652      * @param buffer the buffer into which data is to be read.
653      * @param offset the offset into the buffer at which data is stored.
654      * @param length the amount of data to read
655      *
656      * @return the number of bytes read
657      *
658      * @exception IOException if the data cannot be read
659      */

660     protected synchronized int handleInput(byte[] buffer, int offset,
661                                            int length) throws IOException JavaDoc {
662         if (inputStream == null) {
663             return managingTask.getProject().defaultInput(buffer, offset,
664                                                           length);
665         } else {
666             return inputStream.read(buffer, offset, length);
667         }
668     }
669
670     /**
671      * Process data due to a flush operation.
672      *
673      * @param output the data being flushed.
674      */

675     protected synchronized void handleFlush(String JavaDoc output) {
676         if (outPrintStream == null) {
677             outPrintStream = new PrintStream JavaDoc(outputStream);
678         }
679         outPrintStream.print(output);
680         outPrintStream.flush();
681     }
682
683     /**
684      * Process error output
685      *
686      * @param output the error output data.
687      */

688     protected synchronized void handleErrorOutput(String JavaDoc output) {
689         if (errorPrintStream == null) {
690             errorPrintStream = new PrintStream JavaDoc(errorStream);
691         }
692         errorPrintStream.print(output);
693     }
694
695     /**
696      * Handle a flush operation on the error stream
697      *
698      * @param output the error information being flushed.
699      */

700     protected synchronized void handleErrorFlush(String JavaDoc output) {
701         if (errorPrintStream == null) {
702             errorPrintStream = new PrintStream JavaDoc(errorStream);
703         }
704         errorPrintStream.print(output);
705     }
706
707     /**
708      * Get the output stream for the redirector
709      *
710      * @return the redirector's output stream or null if no output
711      * has been configured
712      */

713     public synchronized OutputStream JavaDoc getOutputStream() {
714         return outputStream;
715     }
716
717     /**
718      * Get the error stream for the redirector
719      *
720      * @return the redirector's error stream or null if no output
721      * has been configured
722      */

723     public synchronized OutputStream JavaDoc getErrorStream() {
724         return errorStream;
725     }
726
727     /**
728      * Get the input stream for the redirector
729      *
730      * @return the redirector's input stream or null if no output
731      * has been configured
732      */

733     public synchronized InputStream JavaDoc getInputStream() {
734         return inputStream;
735     }
736
737     /**
738      * Complete redirection.
739      *
740      * This operation will close any streams and create any specified
741      * property values.
742      *
743      * @throws IOException if the output properties cannot be read from their
744      * output streams.
745      */

746     public synchronized void complete() throws IOException JavaDoc {
747         System.out.flush();
748         System.err.flush();
749
750         if (inputStream != null) {
751             inputStream.close();
752         }
753
754         outputStream.flush();
755         outputStream.close();
756
757         errorStream.flush();
758         errorStream.close();
759
760         //wait for the StreamPumpers to finish
761
while (threadGroup.activeCount() > 0) {
762             try {
763                 managingTask.log("waiting for " + threadGroup.activeCount()
764                     + " Threads:", Project.MSG_DEBUG);
765                 Thread JavaDoc[] thread = new Thread JavaDoc[threadGroup.activeCount()];
766                 threadGroup.enumerate(thread);
767                 for (int i = 0; i < thread.length && thread[i] != null; i++) {
768                     try {
769                         managingTask.log(thread[i].toString(), Project.MSG_DEBUG);
770                     } catch (NullPointerException JavaDoc enPeaEx) {
771                         // Ignore exception
772
}
773                 }
774                 wait(1000);
775             } catch (InterruptedException JavaDoc eyeEx) {
776                 // Ignore exception
777
}
778         }
779
780         setProperties();
781
782         inputStream = null;
783         outputStream = null;
784         errorStream = null;
785         outPrintStream = null;
786         errorPrintStream = null;
787    }
788
789     /**
790      * Notify the <code>Redirector</code> that it is now okay
791      * to set any output and/or error properties.
792      */

793     public synchronized void setProperties() {
794         if (baos != null) {
795             try {
796                 baos.close();
797             } catch (IOException JavaDoc eyeOhEx) {
798                 // Ignore exception
799
}
800         }
801         if (errorBaos != null) {
802             try {
803                 errorBaos.close();
804             } catch (IOException JavaDoc eyeOhEx) {
805                 // Ignore exception
806
}
807         }
808     }
809
810     private OutputStream JavaDoc foldFiles(File JavaDoc[] file, String JavaDoc logHead, int loglevel) {
811         OutputStream JavaDoc result
812             = new LazyFileOutputStream(file[0], append, createEmptyFiles);
813
814         managingTask.log(logHead + file[0], loglevel);
815         char[] c = new char[logHead.length()];
816         Arrays.fill(c, ' ');
817         String JavaDoc indent = new String JavaDoc(c);
818
819         for (int i = 1; i < file.length; i++) {
820             outputStream = new TeeOutputStream(outputStream,
821                 new LazyFileOutputStream(file[i], append, createEmptyFiles));
822             managingTask.log(indent + file[i], loglevel);
823         }
824         return result;
825     }
826 }
827
Popular Tags