source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/types/RedirectorElement.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 19.3 KB
Line 
1/*
2 * Copyright 2004-2005 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17package org.apache.tools.ant.types;
18
19import java.io.File;
20import java.util.Stack;
21import java.util.Vector;
22import java.util.Iterator;
23import java.util.ArrayList;
24
25import org.apache.tools.ant.Project;
26import org.apache.tools.ant.BuildException;
27import org.apache.tools.ant.taskdefs.Redirector;
28
29/**
30 * Element representation of a <CODE>Redirector</CODE>.
31 */
32public class RedirectorElement extends DataType {
33
34 /**
35 * Whether the input mapper was set via <CODE>setOutput</CODE>.
36 */
37 private boolean usingInput = false;
38
39 /**
40 * Whether the output mapper was set via <CODE>setOutput</CODE>.
41 */
42 private boolean usingOutput = false;
43
44 /**
45 * Whether the error mapper was set via <CODE>setError</CODE>.
46 */
47 private boolean usingError = false;
48
49 /**
50 * Indicates if standard error should be logged to Ant's log system
51 * rather than the output. This has no effect if standard error is
52 * redirected to a file or property.
53 */
54 private Boolean logError;
55
56 /** The name of the property into which output is to be stored */
57 private String outputProperty;
58
59 /** The name of the property into which error output is to be stored */
60 private String errorProperty;
61
62 /** String from which input is taken */
63 private String inputString;
64
65 /** Flag which indicates if error and output files are to be appended. */
66 private Boolean append;
67
68 /** Flag which indicates that output should be always sent to the log */
69 private Boolean alwaysLog;
70
71 /** Flag which indicates whether files should be created even if empty. */
72 private Boolean createEmptyFiles;
73
74 /** Input file mapper. */
75 private Mapper inputMapper;
76
77 /** Output file mapper. */
78 private Mapper outputMapper;
79
80 /** Error file mapper. */
81 private Mapper errorMapper;
82
83 /** input filter chains. */
84 private Vector inputFilterChains = new Vector();
85
86 /** output filter chains. */
87 private Vector outputFilterChains = new Vector();
88
89 /** error filter chains. */
90 private Vector errorFilterChains = new Vector();
91
92 /** The output encoding */
93 private String outputEncoding;
94
95 /** The error encoding */
96 private String errorEncoding;
97
98 /** The input encoding */
99 private String inputEncoding;
100
101 /**
102 * Add the input file mapper.
103 * @param inputMapper <CODE>Mapper</CODE>.
104 */
105 public void addConfiguredInputMapper(Mapper inputMapper) {
106 if (isReference()) {
107 throw noChildrenAllowed();
108 }
109 if (this.inputMapper != null) {
110 if (usingInput) {
111 throw new BuildException("attribute \"input\""
112 + " cannot coexist with a nested <inputmapper>");
113 } else {
114 throw new BuildException("Cannot have > 1 <inputmapper>");
115 }
116 }
117 this.inputMapper = inputMapper;
118 }
119
120 /**
121 * Add the output file mapper.
122 * @param outputMapper <CODE>Mapper</CODE>.
123 */
124 public void addConfiguredOutputMapper(Mapper outputMapper) {
125 if (isReference()) {
126 throw noChildrenAllowed();
127 }
128 if (this.outputMapper != null) {
129 if (usingOutput) {
130 throw new BuildException("attribute \"output\""
131 + " cannot coexist with a nested <outputmapper>");
132 } else {
133 throw new BuildException("Cannot have > 1 <outputmapper>");
134 }
135 }
136 this.outputMapper = outputMapper;
137 }
138
139 /**
140 * Add the error file mapper.
141 * @param errorMapper <CODE>Mapper</CODE>.
142 */
143 public void addConfiguredErrorMapper(Mapper errorMapper) {
144 if (isReference()) {
145 throw noChildrenAllowed();
146 }
147 if (this.errorMapper != null) {
148 if (usingError) {
149 throw new BuildException("attribute \"error\""
150 + " cannot coexist with a nested <errormapper>");
151 } else {
152 throw new BuildException("Cannot have > 1 <errormapper>");
153 }
154 }
155 this.errorMapper = errorMapper;
156 }
157
158 /**
159 * Makes this instance in effect a reference to another instance.
160 *
161 * <p>You must not set another attribute or nest elements inside
162 * this element if you make it a reference.</p>
163 * @param r the reference to use
164 * @throws BuildException on error
165 */
166 public void setRefid(Reference r) throws BuildException {
167 if (usingInput
168 || usingOutput
169 || usingError
170 || inputString != null
171 || logError != null
172 || append != null
173 || createEmptyFiles != null
174 || inputEncoding != null
175 || outputEncoding != null
176 || errorEncoding != null
177 || outputProperty != null
178 || errorProperty != null) {
179 throw tooManyAttributes();
180 }
181 super.setRefid(r);
182 }
183
184 /**
185 * Set the input to use for the task
186 * @param input the file from which input is read.
187 */
188 public void setInput(File input) {
189 if (isReference()) {
190 throw tooManyAttributes();
191 }
192 if (inputString != null) {
193 throw new BuildException("The \"input\" and \"inputstring\" "
194 + "attributes cannot both be specified");
195 }
196 usingInput = true;
197 inputMapper = createMergeMapper(input);
198 }
199
200 /**
201 * Set the string to use as input
202 * @param inputString the string which is used as the input source
203 */
204 public void setInputString(String inputString) {
205 if (isReference()) {
206 throw tooManyAttributes();
207 }
208 if (usingInput) {
209 throw new BuildException("The \"input\" and \"inputstring\" "
210 + "attributes cannot both be specified");
211 }
212 this.inputString = inputString;
213 }
214
215 /**
216 * File the output of the process is redirected to. If error is not
217 * redirected, it too will appear in the output
218 *
219 * @param out the file to which output stream is written
220 */
221 public void setOutput(File out) {
222 if (isReference()) {
223 throw tooManyAttributes();
224 }
225 if (out == null) {
226 throw new IllegalArgumentException("output file specified as null");
227 }
228 usingOutput = true;
229 outputMapper = createMergeMapper(out);
230 }
231
232 /**
233 * Set the output encoding.
234 * @param outputEncoding <CODE>String</CODE>.
235 */
236 public void setOutputEncoding(String outputEncoding) {
237 if (isReference()) {
238 throw tooManyAttributes();
239 }
240 this.outputEncoding = outputEncoding;
241 }
242
243 /**
244 * Set the error encoding.
245 *
246 * @param errorEncoding <CODE>String</CODE>.
247 */
248 public void setErrorEncoding(String errorEncoding) {
249 if (isReference()) {
250 throw tooManyAttributes();
251 }
252 this.errorEncoding = errorEncoding;
253 }
254
255 /**
256 * Set the input encoding.
257 * @param inputEncoding <CODE>String</CODE>.
258 */
259 public void setInputEncoding(String inputEncoding) {
260 if (isReference()) {
261 throw tooManyAttributes();
262 }
263 this.inputEncoding = inputEncoding;
264 }
265
266 /**
267 * Controls whether error output of exec is logged. This is only useful
268 * when output is being redirected and error output is desired in the
269 * Ant log
270 * @param logError if true the standard error is sent to the Ant log system
271 * and not sent to output.
272 */
273 public void setLogError(boolean logError) {
274 if (isReference()) {
275 throw tooManyAttributes();
276 }
277 this.logError = ((logError) ? Boolean.TRUE : Boolean.FALSE);
278 }
279
280 /**
281 * Set the file to which standard error is to be redirected.
282 * @param error the file to which error is to be written
283 */
284 public void setError(File error) {
285 if (isReference()) {
286 throw tooManyAttributes();
287 }
288 if (error == null) {
289 throw new IllegalArgumentException("error file specified as null");
290 }
291 usingError = true;
292 errorMapper = createMergeMapper(error);
293 }
294
295 /**
296 * Property name whose value should be set to the output of
297 * the process.
298 * @param outputProperty the name of the property to be set with the
299 * task's output.
300 */
301 public void setOutputProperty(String outputProperty) {
302 if (isReference()) {
303 throw tooManyAttributes();
304 }
305 this.outputProperty = outputProperty;
306 }
307
308 /**
309 * Whether output should be appended to or overwrite an existing file.
310 * Defaults to false.
311 * @param append if true output and error streams are appended to their
312 * respective files, if specified.
313 */
314 public void setAppend(boolean append) {
315 if (isReference()) {
316 throw tooManyAttributes();
317 }
318 this.append = ((append) ? Boolean.TRUE : Boolean.FALSE);
319 }
320
321 /**
322 * If true, (error and non-error) output will be "teed", redirected
323 * as specified while being sent to Ant's logging mechanism as if no
324 * redirection had taken place. Defaults to false.
325 * @param alwaysLog <code>boolean</code>
326 * @since Ant 1.6.3
327 */
328 public void setAlwaysLog(boolean alwaysLog) {
329 if (isReference()) {
330 throw tooManyAttributes();
331 }
332 this.alwaysLog = ((alwaysLog) ? Boolean.TRUE : Boolean.FALSE);
333 }
334
335 /**
336 * Whether output and error files should be created even when empty.
337 * Defaults to true.
338 * @param createEmptyFiles <CODE>boolean</CODE>.
339 */
340 public void setCreateEmptyFiles(boolean createEmptyFiles) {
341 if (isReference()) {
342 throw tooManyAttributes();
343 }
344 this.createEmptyFiles = ((createEmptyFiles)
345 ? Boolean.TRUE : Boolean.FALSE);
346 }
347
348 /**
349 * Property name whose value should be set to the error of
350 * the process.
351 * @param errorProperty the name of the property to be set
352 * with the error output.
353 */
354 public void setErrorProperty(String errorProperty) {
355 if (isReference()) {
356 throw tooManyAttributes();
357 }
358 this.errorProperty = errorProperty;
359 }
360
361 /**
362 * Create a nested input <CODE>FilterChain</CODE>.
363 * @return <CODE>FilterChain</CODE>.
364 */
365 public FilterChain createInputFilterChain() {
366 if (isReference()) {
367 throw noChildrenAllowed();
368 }
369 FilterChain result = new FilterChain();
370 result.setProject(getProject());
371 inputFilterChains.add(result);
372 return result;
373 }
374
375 /**
376 * Create a nested output <CODE>FilterChain</CODE>.
377 * @return <CODE>FilterChain</CODE>.
378 */
379 public FilterChain createOutputFilterChain() {
380 if (isReference()) {
381 throw noChildrenAllowed();
382 }
383 FilterChain result = new FilterChain();
384 result.setProject(getProject());
385 outputFilterChains.add(result);
386 return result;
387 }
388
389 /**
390 * Create a nested error <CODE>FilterChain</CODE>.
391 * @return <CODE>FilterChain</CODE>.
392 */
393 public FilterChain createErrorFilterChain() {
394 if (isReference()) {
395 throw noChildrenAllowed();
396 }
397 FilterChain result = new FilterChain();
398 result.setProject(getProject());
399 errorFilterChains.add(result);
400 return result;
401 }
402
403 /**
404 * Configure the specified <CODE>Redirector</CODE>.
405 * @param redirector <CODE>Redirector</CODE>.
406 */
407 public void configure(Redirector redirector) {
408 configure(redirector, null);
409 }
410
411 /**
412 * Configure the specified <CODE>Redirector</CODE>
413 * for the specified sourcefile.
414 * @param redirector <CODE>Redirector</CODE>.
415 * @param sourcefile <CODE>String</CODE>.
416 */
417 public void configure(Redirector redirector, String sourcefile) {
418 if (isReference()) {
419 getRef().configure(redirector, sourcefile);
420 return;
421 }
422 if (alwaysLog != null) {
423 redirector.setAlwaysLog(alwaysLog.booleanValue());
424 }
425 if (logError != null) {
426 redirector.setLogError(logError.booleanValue());
427 }
428 if (append != null) {
429 redirector.setAppend(append.booleanValue());
430 }
431 if (createEmptyFiles != null) {
432 redirector.setCreateEmptyFiles(createEmptyFiles.booleanValue());
433 }
434 if (outputProperty != null) {
435 redirector.setOutputProperty(outputProperty);
436 }
437 if (errorProperty != null) {
438 redirector.setErrorProperty(errorProperty);
439 }
440 if (inputString != null) {
441 redirector.setInputString(inputString);
442 }
443 if (inputMapper != null) {
444 String[] inputTargets = null;
445 try {
446 inputTargets =
447 inputMapper.getImplementation().mapFileName(sourcefile);
448 } catch (NullPointerException enPeaEx) {
449 if (sourcefile != null) {
450 throw enPeaEx;
451 }
452 }
453 if (inputTargets != null && inputTargets.length > 0) {
454 redirector.setInput(toFileArray(inputTargets));
455 }
456 }
457 if (outputMapper != null) {
458 String[] outputTargets = null;
459 try {
460 outputTargets =
461 outputMapper.getImplementation().mapFileName(sourcefile);
462 } catch (NullPointerException enPeaEx) {
463 if (sourcefile != null) {
464 throw enPeaEx;
465 }
466 }
467 if (outputTargets != null && outputTargets.length > 0) {
468 redirector.setOutput(toFileArray(outputTargets));
469 }
470 }
471 if (errorMapper != null) {
472 String[] errorTargets = null;
473 try {
474 errorTargets =
475 errorMapper.getImplementation().mapFileName(sourcefile);
476 } catch (NullPointerException enPeaEx) {
477 if (sourcefile != null) {
478 throw enPeaEx;
479 }
480 }
481 if (errorTargets != null && errorTargets.length > 0) {
482 redirector.setError(toFileArray(errorTargets));
483 }
484 }
485 if (inputFilterChains.size() > 0) {
486 redirector.setInputFilterChains(inputFilterChains);
487 }
488 if (outputFilterChains.size() > 0) {
489 redirector.setOutputFilterChains(outputFilterChains);
490 }
491 if (errorFilterChains.size() > 0) {
492 redirector.setErrorFilterChains(errorFilterChains);
493 }
494 if (inputEncoding != null) {
495 redirector.setInputEncoding(inputEncoding);
496 }
497 if (outputEncoding != null) {
498 redirector.setOutputEncoding(outputEncoding);
499 }
500 if (errorEncoding != null) {
501 redirector.setErrorEncoding(errorEncoding);
502 }
503 }
504
505 /**
506 * Create a merge mapper pointing to the specified destination file.
507 * @param destfile <CODE>File</CODE>
508 * @return <CODE>Mapper</CODE>.
509 */
510 protected Mapper createMergeMapper(File destfile) {
511 Mapper result = new Mapper(getProject());
512 result.setClassname(
513 org.apache.tools.ant.util.MergingMapper.class.getName());
514 result.setTo(destfile.getAbsolutePath());
515 return result;
516 }
517
518 /**
519 * Return a <CODE>File[]</CODE> from the specified set of filenames.
520 * @param name <CODE>String[]</CODE>
521 * @return <CODE>File[]</CODE>.
522 */
523 protected File[] toFileArray(String[] name) {
524 if (name == null) {
525 return null;
526 }
527 //remove any null elements
528 ArrayList list = new ArrayList(name.length);
529 for (int i = 0; i < name.length; i++) {
530 if (name[i] != null) {
531 list.add(getProject().resolveFile(name[i]));
532 }
533 }
534 return (File[]) (list.toArray(new File[list.size()]));
535 }
536
537 /**
538 * Convenience method.
539 * @throws BuildException on error.
540 */
541 protected void dieOnCircularReference() throws BuildException {
542 if (isChecked()) {
543 return;
544 }
545 Stack s = new Stack();
546 s.push(this);
547 dieOnCircularReference(s, getProject());
548 }
549
550 /**
551 * Overrides the version of DataType to recurse on all DataType
552 * child elements that may have been added.
553 * @param stk the stack of data types to use (recursively).
554 * @param p the project to use to dereference the references.
555 * @throws BuildException on error.
556 */
557 protected void dieOnCircularReference(Stack stk, Project p)
558 throws BuildException {
559 if (isChecked()) {
560 return;
561 }
562 if (isReference()) {
563 super.dieOnCircularReference(stk, p);
564 } else {
565 Mapper[] m = new Mapper[] {inputMapper, outputMapper, errorMapper};
566 for (int i = 0; i < m.length; i++) {
567 if (m[i] != null) {
568 stk.push(m[i]);
569 m[i].dieOnCircularReference(stk, p);
570 stk.pop();
571 }
572 }
573 Vector[] v = new Vector[]
574 {inputFilterChains, outputFilterChains, errorFilterChains};
575 for (int i = 0; i < v.length; i++) {
576 if (v[i] != null) {
577 for (Iterator fci = v[i].iterator(); fci.hasNext();) {
578 FilterChain fc = (FilterChain) fci.next();
579 stk.push(fc);
580 fc.dieOnCircularReference(stk, p);
581 stk.pop();
582 }
583 }
584 }
585 setChecked(true);
586 }
587 }
588
589 /**
590 * Perform the check for circular references, returning the
591 * referenced RedirectorElement
592 * @return the referenced RedirectorElement.
593 */
594 private RedirectorElement getRef() {
595 dieOnCircularReference();
596 Object o = getRefid().getReferencedObject(getProject());
597 if (!(o instanceof RedirectorElement)) {
598 throw new BuildException(getRefid().getRefId()
599 + " doesn\'t denote a RedirectorElement");
600 }
601 return (RedirectorElement) o;
602 }
603
604}
Note: See TracBrowser for help on using the repository browser.