KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > capture > CaptureStreamsTask


1 /**
2  * $Id: CaptureStreamsTask.java 180 2007-03-15 12:56:38Z ssmc $
3  * Copyright 2003-2005 iDare Media, Inc. All rights reserved.
4  *
5  * Originally written by iDare Media, Inc. for release into the public domain. This
6  * library, source form and binary form, is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License (LGPL) as published
8  * by the Free Software Foundation; either version 2.1 of the License, or (at your option)
9  * any later version.<p>
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU LGPL for more details.<p>
14  *
15  * You should have received a copy of the GNU Lesser General Public License along with this
16  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite
17  * 330, Boston, MA 02111-1307 USA. The GNU LGPL can be found online at
18  * http://www.fsf.org/copyleft/lesser.html<p>
19  *
20  * This product has been influenced by several projects within the open-source community.
21  * The JWare developers wish to acknowledge the open-source community's support. For more
22  * information regarding the open-source products used within JWare, please visit the
23  * JWare website.
24  *----------------------------------------------------------------------------------------*
25  * WEBSITE- http://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.capture;
30
31 import java.io.PrintStream JavaDoc;
32
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.Project;
35
36 import com.idaremedia.antx.AntX;
37 import com.idaremedia.antx.NoiseLevel;
38 import com.idaremedia.antx.apis.BuildError;
39 import com.idaremedia.antx.apis.ProblemHandler;
40 import com.idaremedia.antx.apis.Responses;
41 import com.idaremedia.antx.ownhelpers.FeedbackSink;
42 import com.idaremedia.antx.starters.TaskSet;
43
44 /**
45  * Execution "net" task that captures all output to either
46  * <span class="src">System</span> (or stdio) stream. The enclosing application
47  * context must have the property permission to replace the System stream
48  * handlers. Like CaptureLogsTask, CaptureStreamsTasks can be nested (but are not
49  * usually).
50  * <p>
51  * The CaptureStreamsTask has a (immutable) predefined notion of "important" events.
52  * If either system stream is being captured (singlely) then all of the information
53  * written to that stream is considered important. If both streams are being captured,
54  * anything written to the <span class="src">System.err</span> stream is considered
55  * important.
56  * <p>
57  * You can easily extend the CaptureStreamsTask to capture additional kinds of
58  * execution context; refer to the {@linkplain #performTheEnclosedTaskList} method.
59  * <p>
60  * <b>Example Usage:</b><pre>
61  * &lt;captureoutput&gt;
62  * &lt;...<i>Your Tasks Here</i>&gt;
63  * &lt;copylogged from="stdio" important="no" tofile="..."/&gt;
64  * &lt;/captureoutput&gt;
65  *
66  * &lt;captureoutput fromstream="stderr"&gt;
67  * &lt;...<i>Your Tasks Here</i>&gt;
68  * &lt;copylogged from="stdio" toproperty="my.errs"/&gt;
69  * &lt;/captureoutput&gt;
70  * &lt;assert equals="" property="my.errs"/&gt;
71  * </pre>
72  *
73  * @since JWare/AntX 0.3
74  * @author ssmc, &copy;2003-2005 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
75  * @version 0.5
76  * @.safety single
77  * @.group impl,helper
78  * @see CaptureLogsTask
79  **/

80
81 public class CaptureStreamsTask extends TaskSet implements LogsRecorder
82 {
83     /**
84      * Initializes a new CaptureStreamsTask instance.
85      **/

86     public CaptureStreamsTask()
87     {
88         super(AntX.capture+"CaptureStreamsTask:");
89     }
90
91
92     /**
93      * Initializes a new CV-labeled CaptureStreamsTask instance.
94      * @param iam CV-label (non-null)
95      **/

96     public CaptureStreamsTask(String JavaDoc iam)
97     {
98         super(iam);
99     }
100
101
102
103     /**
104      * Sets the stream from which this task will capture output.
105      * Must be one of [<span class="src">{@linkplain FeedbackSink#STDIO}</span>,
106      * <span class="src">{@linkplain FeedbackSink#STDERR}</span>,
107      * <span class="src">{@linkplain FeedbackSink#STDOUT}</span>].
108      * @param ss system stream (non-null)
109      * @throws BuildException if bad source defined
110      **/

111     public void setFromStream(FeedbackSink ss)
112     {
113         require_(ss!=null, "setstrm- err|out|both");
114
115         if (!FeedbackSink.isSystem(ss)) {
116             String JavaDoc ermsg = getAntXMsg("brul.logs.bad.capture.sink",
117                                       getTaskName(),ss.getValue());
118             log(ermsg,Project.MSG_ERR);
119             throw new BuildException(ermsg,getLocation());
120         }
121         m_streamChoice = ss;
122     }
123
124
125
126     /**
127      * Returns the capture stream choice for this task. If never set,
128      * defaults to <span class="src">{@linkplain FeedbackSink#STDIO}</span>
129      * to capture both System err and out streams.
130      **/

131     public FeedbackSink getFromStream()
132     {
133         return m_streamChoice;
134     }
135
136
137
138     /**
139      * Returns <i>true</i> if this task would consider the given
140      * noise level important.
141      * @param nl noise level (non-null)
142      **/

143     public final boolean isImportant(NoiseLevel nl)
144     {
145         require_(nl!=null,"isImportnt- nonzro NL");
146         if (NoiseLevel.isAsBadAs(nl,NoiseLevel.WARNING)) {
147             return true;
148         }
149         return false;
150     }
151
152
153
154     /**
155      * Returns a <em>copy</em> of current main stream buffer's contents.
156      * If both streams are being captured, this method returns the contents
157      * of the <span class="src">System.err</span> stream. Returns an empty
158      * string if nothing being captured.
159      **/

160     public String JavaDoc copyOfImportantLogs()
161     {
162         if (m_mainFilterStream!=null) {
163             return m_mainFilterStream.copyBuffer();
164         }
165         return "";
166     }
167
168
169
170     /**
171      * Returns a <em>copy</em> of the current secondary stream buffer's
172      * contents or the empty string if not such stream. When tracking
173      * both streams, this method returns the messages written to the
174      * <span class="src">System.out</span> stream. Never returns <i>null</i>.
175      **/

176     public String JavaDoc copyOfSecondaryLogs()
177     {
178         if (m_secondFilterStream!=null) {
179             return m_secondFilterStream.copyBuffer();
180         }
181         return "";
182     }
183
184
185
186     /**
187      * Returns a <em>copy</em> of all content captured by this task
188      * so far. This can include all the messages written to the standard
189      * <span class="src">System.err</span> stream and the standard
190      * <span class="src">System.out</span> stream if both are being
191      * captured. The ordering of the contents is determined by the
192      * locking policies of the underlying streams.
193      * @see #copyOfImportantLogs
194      **/

195     public String JavaDoc copyOfAllLogs()
196     {
197         if (m_allBuffer!=null) {
198             return m_allBuffer.substring(0);
199         }
200         return m_mainFilterStream.copyBuffer();
201     }
202
203
204
205     /**
206      * Resets this task's buffers as iff no messages ever recorded.
207      **/

208     public void clearLogs()
209     {
210         if (m_allBuffer!=null) {
211             m_allBuffer.delete(0,m_allBuffer.length());
212         }
213         if (m_secondFilterStream!=null) {
214             m_secondFilterStream.clearBuffer();
215         }
216         if (m_mainFilterStream!=null) {
217             m_mainFilterStream.clearBuffer();
218         }
219     }
220
221
222
223     /**
224      * Clears contents of all of this task's capture buffers and
225      * resets references to <i>null</i>. Called by the
226      * <span class="src">perform</span> method to cleanup after
227      * execution (successful or not). If you override this method
228      * you <em>must</em> call this method from your subclassed
229      * method.
230      **/

231     protected void uninstallBuffers()
232     {
233         sysOut = null;
234         sysErr = null;
235
236         if (m_allBuffer!=null) {
237             m_allBuffer.delete(0,m_allBuffer.length());
238             m_allBuffer = null;
239         }
240         if (m_secondFilterStream!=null) {
241             m_secondFilterStream.clearBuffer();
242             m_secondFilterStream = null;
243         }
244         if (m_mainFilterStream!=null) {
245             m_mainFilterStream.clearBuffer();
246             m_mainFilterStream = null;
247         }
248     }
249
250
251
252     /**
253      * Template method to start capturing messages written to both
254      * system streams to this task's backup buffers and calls nested
255      * tasks. Your subclass is more likely to need to customize one
256      * of the methods called by this template instead of the template
257      * itself.
258      * @throws SecurityException if enclosing context does not have
259      * permission to swap in/out the required streams.
260      * @throws BuildException if the underlying (un)capture mechanism
261      * does.
262      * @see #startCapturing
263      * @see #stopCapturing stopCapturing()
264      * @see #performTheEnclosedTaskList
265      * @see #uninstallBuffers
266      **/

267     protected void performNestedTasks()
268     {
269         Throwable JavaDoc uncaught=null;
270         try {
271             startCapturing();
272             performTheEnclosedTaskList();
273         } catch(Throwable JavaDoc anyX) {
274             uncaught = anyX;
275             if (anyX instanceof RuntimeException JavaDoc) {
276                 throw (RuntimeException JavaDoc)anyX;
277             }
278             throw (Error JavaDoc)anyX;
279         } finally {
280             stopCapturing(uncaught);
281             uninstallBuffers();
282         }
283     }
284
285
286
287     /**
288      * Called to execute this taskset's nested task from the wrapped
289      * {@linkplain #performNestedTasks} method. This method is a convenient
290      * extension point for subclasses and other tasks that want to capture
291      * stdio information without overriding the standard way to do this.
292      * @since JWare/AntX 0.4
293      **/

294     protected void performTheEnclosedTaskList()
295     {
296         performTheTasksList();
297     }
298
299
300
301     /**
302      * Template method called to start capturing the various
303      * <span class="src">System</span> streams. This method is called
304      * just before the nested tasks are performed. The default
305      * implementation replaces the current System streams with our own
306      * decorators; the current system streams are still written to after
307      * we've saved the information. Subclasses <em>must</em> call this
308      * method (first) if they want to capture System output.
309      * @throws SecurityException if enclosing context does not have
310      * permission to swap in/out System streams.
311      * @throws BuildException if the stream-to-be-captured is not one
312      * of the standard System streams
313      * @since JWare/AntX 0.4
314      **/

315     protected void startCapturing()
316     {
317         verify_(!m_netInstalled,"perform- not installed");
318         verify_(!m_strmSwitched,"perform- not partially installed");
319
320         if (shouldCapture(FeedbackSink.STDIO)) {
321
322             System.out.flush();
323             sysOut = System.out;
324
325             System.err.flush();
326             sysErr = System.err;
327
328             PrintStream JavaDoc filtered;
329             FeedbackSink ss = getFromStream();
330
331             switch (ss.getIndex()) {
332                 case FeedbackSink.STDIO_INDEX: {
333                     m_allBuffer = new StringBuffer JavaDoc(320);
334                     m_secondFilterStream = new MimOutputStream(sysOut,m_allBuffer);
335                     filtered = new PrintStream JavaDoc(m_secondFilterStream);
336                     System.setOut(filtered);
337                     //fallthru 4 err (ssmc)
338
}
339                 case FeedbackSink.STDERR_INDEX: {
340                     m_mainFilterStream = new MimOutputStream(sysErr,m_allBuffer);
341                     filtered = new PrintStream JavaDoc(m_mainFilterStream);
342                     System.setErr(filtered);
343                     break;
344                 }
345                 case FeedbackSink.STDOUT_INDEX: {
346                     m_mainFilterStream = new MimOutputStream(sysOut,m_allBuffer);
347                     filtered = new PrintStream JavaDoc(m_mainFilterStream);
348                     System.setOut(filtered);
349                     break;
350                 }
351                 default: {
352                     throw new BuildError(ss.getValue());//never!
353
}
354             }
355             m_strmSwitched = true;
356
357             CapturedLogs.installStdIORecorder(this, m_errHandler);
358
359             m_netInstalled = true;
360         }
361     }
362
363
364
365     /**
366      * Template method called after the nestes tasks have been
367      * performed but while the <span class="src">System</span>
368      * streams are still being captured. No-op by default.
369      * @param cause [optional] error that stopped execution
370      * @since JWare/AntX 0.4
371      **/

372     protected void stopCapturing(Throwable JavaDoc cause)
373     {
374         if (m_netInstalled) {
375             m_netInstalled = false;
376             CapturedLogs.unwindStdIORecorder(m_errHandler);
377         }
378         if (m_strmSwitched) {//@.bug Fix for if only 1 swapped!
379
System.setOut(sysOut);
380             System.setErr(sysErr);
381         }
382     }
383
384
385     /**
386      * Filter that determines what information should captured
387      * by this task. By default returns <i>true</i> for everything.
388      * @param sel [unused] thing to be captured (non-null)
389      * @since JWare/AntX 0.4
390      **/

391     protected boolean shouldCapture(FeedbackSink sel)
392     {
393         return true;
394     }
395
396
397     private volatile boolean m_netInstalled;
398     private boolean m_strmSwitched;
399     private ProblemHandler m_errHandler = new Responses.LogUsing(this);
400     private StringBuffer JavaDoc m_allBuffer;
401     private MimOutputStream m_secondFilterStream, m_mainFilterStream;
402     private FeedbackSink m_streamChoice= FeedbackSink.STDIO;//err+out
403
private PrintStream JavaDoc sysOut;
404     private PrintStream JavaDoc sysErr;
405 }
406
407 /* end-of-CaptureStreamsTask.java */
408
Popular Tags