KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > Project


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
19 package org.apache.tools.ant;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.EOFException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.lang.reflect.Modifier JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Properties JavaDoc;
32 import java.util.Stack JavaDoc;
33 import java.util.Vector JavaDoc;
34 import java.util.Set JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.WeakHashMap JavaDoc;
39 import org.apache.tools.ant.input.DefaultInputHandler;
40 import org.apache.tools.ant.input.InputHandler;
41 import org.apache.tools.ant.helper.DefaultExecutor;
42 import org.apache.tools.ant.types.FilterSet;
43 import org.apache.tools.ant.types.FilterSetCollection;
44 import org.apache.tools.ant.types.Description;
45 import org.apache.tools.ant.types.Path;
46 import org.apache.tools.ant.types.Resource;
47 import org.apache.tools.ant.types.ResourceFactory;
48 import org.apache.tools.ant.types.resources.FileResource;
49 import org.apache.tools.ant.util.FileUtils;
50 import org.apache.tools.ant.util.JavaEnvUtils;
51 import org.apache.tools.ant.util.StringUtils;
52
53 /**
54  * Central representation of an Ant project. This class defines an
55  * Ant project with all of its targets, tasks and various other
56  * properties. It also provides the mechanism to kick off a build using
57  * a particular target name.
58  * <p>
59  * This class also encapsulates methods which allow files to be referred
60  * to using abstract path names which are translated to native system
61  * file paths at runtime.
62  *
63  */

64 public class Project implements ResourceFactory {
65     private static final String JavaDoc LINE_SEP = System.getProperty("line.separator");
66
67     /** Message priority of &quot;error&quot;. */
68     public static final int MSG_ERR = 0;
69     /** Message priority of &quot;warning&quot;. */
70     public static final int MSG_WARN = 1;
71     /** Message priority of &quot;information&quot;. */
72     public static final int MSG_INFO = 2;
73     /** Message priority of &quot;verbose&quot;. */
74     public static final int MSG_VERBOSE = 3;
75     /** Message priority of &quot;debug&quot;. */
76     public static final int MSG_DEBUG = 4;
77
78     /**
79      * Constant for the &quot;visiting&quot; state, used when
80      * traversing a DFS of target dependencies.
81      */

82     private static final String JavaDoc VISITING = "VISITING";
83     /**
84      * Constant for the &quot;visited&quot; state, used when
85      * traversing a DFS of target dependencies.
86      */

87     private static final String JavaDoc VISITED = "VISITED";
88
89     /**
90      * Version constant for Java 1.0 .
91      *
92      * @deprecated since 1.5.x.
93      * Use {@link JavaEnvUtils#JAVA_1_0} instead.
94      */

95     public static final String JavaDoc JAVA_1_0 = JavaEnvUtils.JAVA_1_0;
96     /**
97      * Version constant for Java 1.1 .
98      *
99      * @deprecated since 1.5.x.
100      * Use {@link JavaEnvUtils#JAVA_1_1} instead.
101      */

102     public static final String JavaDoc JAVA_1_1 = JavaEnvUtils.JAVA_1_1;
103     /**
104      * Version constant for Java 1.2 .
105      *
106      * @deprecated since 1.5.x.
107      * Use {@link JavaEnvUtils#JAVA_1_2} instead.
108      */

109     public static final String JavaDoc JAVA_1_2 = JavaEnvUtils.JAVA_1_2;
110     /**
111      * Version constant for Java 1.3 .
112      *
113      * @deprecated since 1.5.x.
114      * Use {@link JavaEnvUtils#JAVA_1_3} instead.
115      */

116     public static final String JavaDoc JAVA_1_3 = JavaEnvUtils.JAVA_1_3;
117     /**
118      * Version constant for Java 1.4 .
119      *
120      * @deprecated since 1.5.x.
121      * Use {@link JavaEnvUtils#JAVA_1_4} instead.
122      */

123     public static final String JavaDoc JAVA_1_4 = JavaEnvUtils.JAVA_1_4;
124
125     /** Default filter start token. */
126     public static final String JavaDoc TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
127     /** Default filter end token. */
128     public static final String JavaDoc TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
129
130     /** Instance of a utility class to use for file operations. */
131     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
132
133     /** Name of this project. */
134     private String JavaDoc name;
135     /** Description for this project (if any). */
136     private String JavaDoc description;
137
138
139     /** Map of references within the project (paths etc) (String to Object). */
140     private Hashtable JavaDoc references = new AntRefTable();
141
142     /** Map of id references - used for indicating broken build files */
143     private HashMap JavaDoc idReferences = new HashMap JavaDoc();
144
145     /** the parent project for old id resolution (if inheritreferences is set) */
146     private Project parentIdProject = null;
147
148     /** Name of the project's default target. */
149     private String JavaDoc defaultTarget;
150
151     /** Map from target names to targets (String to Target). */
152     private Hashtable JavaDoc targets = new Hashtable JavaDoc();
153     /** Set of global filters. */
154     private FilterSet globalFilterSet = new FilterSet();
155     {
156         // Initialize the globalFileSet's project
157
globalFilterSet.setProject(this);
158     }
159
160     /**
161      * Wrapper around globalFilterSet. This collection only ever
162      * contains one FilterSet, but the wrapper is needed in order to
163      * make it easier to use the FileUtils interface.
164      */

165     private FilterSetCollection globalFilters
166         = new FilterSetCollection(globalFilterSet);
167
168     /** Project base directory. */
169     private File JavaDoc baseDir;
170
171     /** List of listeners to notify of build events. */
172     private Vector JavaDoc listeners = new Vector JavaDoc();
173
174     /**
175      * The Ant core classloader--may be <code>null</code> if using
176      * parent classloader.
177      */

178     private ClassLoader JavaDoc coreLoader = null;
179
180     /** Records the latest task to be executed on a thread. */
181     private Map JavaDoc/*<Thread,Task>*/ threadTasks = Collections.synchronizedMap(new WeakHashMap JavaDoc());
182
183     /** Records the latest task to be executed on a thread group. */
184     private Map JavaDoc/*<ThreadGroup,Task>*/ threadGroupTasks
185         = Collections.synchronizedMap(new WeakHashMap JavaDoc());
186
187     /**
188      * Called to handle any input requests.
189      */

190     private InputHandler inputHandler = null;
191
192     /**
193      * The default input stream used to read any input.
194      */

195     private InputStream JavaDoc defaultInputStream = null;
196
197     /**
198      * Keep going flag.
199      */

200     private boolean keepGoingMode = false;
201
202     /**
203      * Flag which catches Listeners which try to use System.out or System.err .
204      */

205     private boolean loggingMessage = false;
206
207     /**
208      * Set the input handler.
209      *
210      * @param handler the InputHandler instance to use for gathering input.
211      */

212     public void setInputHandler(InputHandler handler) {
213         inputHandler = handler;
214     }
215
216     /**
217      * Set the default System input stream. Normally this stream is set to
218      * System.in. This inputStream is used when no task input redirection is
219      * being performed.
220      *
221      * @param defaultInputStream the default input stream to use when input
222      * is requested.
223      * @since Ant 1.6
224      */

225     public void setDefaultInputStream(InputStream JavaDoc defaultInputStream) {
226         this.defaultInputStream = defaultInputStream;
227     }
228
229     /**
230      * Get this project's input stream.
231      *
232      * @return the InputStream instance in use by this Project instance to
233      * read input.
234      */

235     public InputStream JavaDoc getDefaultInputStream() {
236         return defaultInputStream;
237     }
238
239     /**
240      * Retrieve the current input handler.
241      *
242      * @return the InputHandler instance currently in place for the project
243      * instance.
244      */

245     public InputHandler getInputHandler() {
246         return inputHandler;
247     }
248
249     /**
250      * Create a new Ant project.
251      */

252     public Project() {
253         inputHandler = new DefaultInputHandler();
254     }
255
256     /**
257      * Create and initialize a subproject. By default the subproject will be of
258      * the same type as its parent. If a no-arg constructor is unavailable, the
259      * <code>Project</code> class will be used.
260      * @return a Project instance configured as a subproject of this Project.
261      * @since Ant 1.7
262      */

263     public Project createSubProject() {
264         Project subProject = null;
265         try {
266             subProject = (Project) (getClass().newInstance());
267         } catch (Exception JavaDoc e) {
268             subProject = new Project();
269         }
270         initSubProject(subProject);
271         return subProject;
272     }
273
274     /**
275      * Initialize a subproject.
276      * @param subProject the subproject to initialize.
277      */

278     public void initSubProject(Project subProject) {
279         ComponentHelper.getComponentHelper(subProject)
280             .initSubProject(ComponentHelper.getComponentHelper(this));
281         subProject.setDefaultInputStream(getDefaultInputStream());
282         subProject.setKeepGoingMode(this.isKeepGoingMode());
283         subProject.setExecutor(getExecutor().getSubProjectExecutor());
284     }
285
286     /**
287      * Initialise the project.
288      *
289      * This involves setting the default task definitions and loading the
290      * system properties.
291      *
292      * @exception BuildException if the default task list cannot be loaded.
293      */

294     public void init() throws BuildException {
295         initProperties();
296
297         ComponentHelper.getComponentHelper(this).initDefaultDefinitions();
298     }
299
300     /**
301      * Initializes the properties.
302      * @exception BuildException if an vital property could not be set.
303      * @since Ant 1.7
304      */

305     public void initProperties() throws BuildException {
306         setJavaVersionProperty();
307         setSystemProperties();
308         setPropertyInternal(MagicNames.ANT_VERSION, Main.getAntVersion());
309         setAntLib();
310     }
311
312     private void setAntLib() {
313         File JavaDoc antlib = org.apache.tools.ant.launch.Locator.getClassSource(
314             Project.class);
315         if (antlib != null) {
316             setPropertyInternal(MagicNames.ANT_LIB, antlib.getAbsolutePath());
317         }
318     }
319     /**
320      * Factory method to create a class loader for loading classes from
321      * a given path.
322      *
323      * @param path the path from which classes are to be loaded.
324      *
325      * @return an appropriate classloader.
326      */

327     public AntClassLoader createClassLoader(Path path) {
328         return new AntClassLoader(
329             getClass().getClassLoader(), this, path);
330     }
331
332     /**
333      * Factory method to create a class loader for loading classes from
334      * a given path.
335      *
336      * @param parent the parent classloader for the new loader.
337      * @param path the path from which classes are to be loaded.
338      *
339      * @return an appropriate classloader.
340      */

341     public AntClassLoader createClassLoader(
342         ClassLoader JavaDoc parent, Path path) {
343         return new AntClassLoader(parent, this, path);
344     }
345
346     /**
347      * Set the core classloader for the project. If a <code>null</code>
348      * classloader is specified, the parent classloader should be used.
349      *
350      * @param coreLoader The classloader to use for the project.
351      * May be <code>null</code>.
352      */

353     public void setCoreLoader(ClassLoader JavaDoc coreLoader) {
354         this.coreLoader = coreLoader;
355     }
356
357     /**
358      * Return the core classloader to use for this project.
359      * This may be <code>null</code>, indicating that
360      * the parent classloader should be used.
361      *
362      * @return the core classloader to use for this project.
363      *
364      */

365     public ClassLoader JavaDoc getCoreLoader() {
366         return coreLoader;
367     }
368
369     /**
370      * Add a build listener to the list. This listener will
371      * be notified of build events for this project.
372      *
373      * @param listener The listener to add to the list.
374      * Must not be <code>null</code>.
375      */

376     public synchronized void addBuildListener(BuildListener listener) {
377         // If the listeners already has this listener, do nothing
378
if (listeners.contains(listener)) {
379             return;
380         }
381         // create a new Vector to avoid ConcurrentModificationExc when
382
// the listeners get added/removed while we are in fire
383
Vector JavaDoc newListeners = getBuildListeners();
384         newListeners.addElement(listener);
385         listeners = newListeners;
386     }
387
388     /**
389      * Remove a build listener from the list. This listener
390      * will no longer be notified of build events for this project.
391      *
392      * @param listener The listener to remove from the list.
393      * Should not be <code>null</code>.
394      */

395     public synchronized void removeBuildListener(BuildListener listener) {
396         // create a new Vector to avoid ConcurrentModificationExc when
397
// the listeners get added/removed while we are in fire
398
Vector JavaDoc newListeners = getBuildListeners();
399         newListeners.removeElement(listener);
400         listeners = newListeners;
401     }
402
403     /**
404      * Return a copy of the list of build listeners for the project.
405      *
406      * @return a list of build listeners for the project
407      */

408     public Vector JavaDoc getBuildListeners() {
409         return (Vector JavaDoc) listeners.clone();
410     }
411
412     /**
413      * Write a message to the log with the default log level
414      * of MSG_INFO .
415      * @param message The text to log. Should not be <code>null</code>.
416      */

417
418     public void log(String JavaDoc message) {
419         log(message, MSG_INFO);
420     }
421
422     /**
423      * Write a project level message to the log with the given log level.
424      * @param message The text to log. Should not be <code>null</code>.
425      * @param msgLevel The log priority level to use.
426      */

427     public void log(String JavaDoc message, int msgLevel) {
428         log(message, null, msgLevel);
429     }
430
431     /**
432      * Write a project level message to the log with the given log level.
433      * @param message The text to log. Should not be <code>null</code>.
434      * @param throwable The exception causing this log, may be <code>null</code>.
435      * @param msgLevel The log priority level to use.
436      * @since 1.7
437      */

438     public void log(String JavaDoc message, Throwable JavaDoc throwable, int msgLevel) {
439         fireMessageLogged(this, message, throwable, msgLevel);
440     }
441
442     /**
443      * Write a task level message to the log with the given log level.
444      * @param task The task to use in the log. Must not be <code>null</code>.
445      * @param message The text to log. Should not be <code>null</code>.
446      * @param msgLevel The log priority level to use.
447      */

448     public void log(Task task, String JavaDoc message, int msgLevel) {
449         fireMessageLogged(task, message, null, msgLevel);
450     }
451
452     /**
453      * Write a task level message to the log with the given log level.
454      * @param task The task to use in the log. Must not be <code>null</code>.
455      * @param message The text to log. Should not be <code>null</code>.
456      * @param throwable The exception causing this log, may be <code>null</code>.
457      * @param msgLevel The log priority level to use.
458      * @since 1.7
459      */

460     public void log(Task task, String JavaDoc message, Throwable JavaDoc throwable, int msgLevel) {
461         fireMessageLogged(task, message, throwable, msgLevel);
462     }
463
464     /**
465      * Write a target level message to the log with the given log level.
466      * @param target The target to use in the log.
467      * Must not be <code>null</code>.
468      * @param message The text to log. Should not be <code>null</code>.
469      * @param msgLevel The log priority level to use.
470      */

471     public void log(Target target, String JavaDoc message, int msgLevel) {
472         log(target, message, null, msgLevel);
473     }
474
475     /**
476      * Write a target level message to the log with the given log level.
477      * @param target The target to use in the log.
478      * Must not be <code>null</code>.
479      * @param message The text to log. Should not be <code>null</code>.
480      * @param throwable The exception causing this log, may be <code>null</code>.
481      * @param msgLevel The log priority level to use.
482      * @since 1.7
483      */

484     public void log(Target target, String JavaDoc message, Throwable JavaDoc throwable,
485             int msgLevel) {
486         fireMessageLogged(target, message, throwable, msgLevel);
487     }
488
489     /**
490      * Return the set of global filters.
491      *
492      * @return the set of global filters.
493      */

494     public FilterSet getGlobalFilterSet() {
495         return globalFilterSet;
496     }
497
498     /**
499      * Set a property. Any existing property of the same name
500      * is overwritten, unless it is a user property.
501      * @param name The name of property to set.
502      * Must not be <code>null</code>.
503      * @param value The new value of the property.
504      * Must not be <code>null</code>.
505      */

506     public void setProperty(String JavaDoc name, String JavaDoc value) {
507         PropertyHelper.getPropertyHelper(this).
508                 setProperty(null, name, value, true);
509     }
510
511     /**
512      * Set a property if no value currently exists. If the property
513      * exists already, a message is logged and the method returns with
514      * no other effect.
515      *
516      * @param name The name of property to set.
517      * Must not be <code>null</code>.
518      * @param value The new value of the property.
519      * Must not be <code>null</code>.
520      * @since 1.5
521      */

522     public void setNewProperty(String JavaDoc name, String JavaDoc value) {
523         PropertyHelper.getPropertyHelper(this).setNewProperty(null, name,
524                                                               value);
525     }
526
527     /**
528      * Set a user property, which cannot be overwritten by
529      * set/unset property calls. Any previous value is overwritten.
530      * @param name The name of property to set.
531      * Must not be <code>null</code>.
532      * @param value The new value of the property.
533      * Must not be <code>null</code>.
534      * @see #setProperty(String,String)
535      */

536     public void setUserProperty(String JavaDoc name, String JavaDoc value) {
537         PropertyHelper.getPropertyHelper(this).setUserProperty(null, name,
538                                                                value);
539     }
540
541     /**
542      * Set a user property, which cannot be overwritten by set/unset
543      * property calls. Any previous value is overwritten. Also marks
544      * these properties as properties that have not come from the
545      * command line.
546      *
547      * @param name The name of property to set.
548      * Must not be <code>null</code>.
549      * @param value The new value of the property.
550      * Must not be <code>null</code>.
551      * @see #setProperty(String,String)
552      */

553     public void setInheritedProperty(String JavaDoc name, String JavaDoc value) {
554         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
555         ph.setInheritedProperty(null, name, value);
556     }
557
558     /**
559      * Set a property unless it is already defined as a user property
560      * (in which case the method returns silently).
561      *
562      * @param name The name of the property.
563      * Must not be <code>null</code>.
564      * @param value The property value. Must not be <code>null</code>.
565      */

566     private void setPropertyInternal(String JavaDoc name, String JavaDoc value) {
567         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
568         ph.setProperty(null, name, value, false);
569     }
570
571     /**
572      * Return the value of a property, if it is set.
573      *
574      * @param propertyName The name of the property.
575      * May be <code>null</code>, in which case
576      * the return value is also <code>null</code>.
577      * @return the property value, or <code>null</code> for no match
578      * or if a <code>null</code> name is provided.
579      */

580     public String JavaDoc getProperty(String JavaDoc propertyName) {
581         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
582         return (String JavaDoc) ph.getProperty(null, propertyName);
583     }
584
585     /**
586      * Replace ${} style constructions in the given value with the
587      * string value of the corresponding data types.
588      *
589      * @param value The string to be scanned for property references.
590      * May be <code>null</code>.
591      *
592      * @return the given string with embedded property names replaced
593      * by values, or <code>null</code> if the given string is
594      * <code>null</code>.
595      *
596      * @exception BuildException if the given value has an unclosed
597      * property name, e.g. <code>${xxx</code>.
598      */

599     public String JavaDoc replaceProperties(String JavaDoc value)
600         throws BuildException {
601         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
602         return ph.replaceProperties(null, value, null);
603     }
604
605     /**
606      * Return the value of a user property, if it is set.
607      *
608      * @param propertyName The name of the property.
609      * May be <code>null</code>, in which case
610      * the return value is also <code>null</code>.
611      * @return the property value, or <code>null</code> for no match
612      * or if a <code>null</code> name is provided.
613      */

614      public String JavaDoc getUserProperty(String JavaDoc propertyName) {
615         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
616         return (String JavaDoc) ph.getUserProperty(null, propertyName);
617     }
618
619     /**
620      * Return a copy of the properties table.
621      * @return a hashtable containing all properties
622      * (including user properties).
623      */

624     public Hashtable JavaDoc getProperties() {
625         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
626         return ph.getProperties();
627     }
628
629     /**
630      * Return a copy of the user property hashtable.
631      * @return a hashtable containing just the user properties.
632      */

633     public Hashtable JavaDoc getUserProperties() {
634         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
635         return ph.getUserProperties();
636     }
637
638     /**
639      * Copy all user properties that have been set on the command
640      * line or a GUI tool from this instance to the Project instance
641      * given as the argument.
642      *
643      * <p>To copy all &quot;user&quot; properties, you will also have to call
644      * {@link #copyInheritedProperties copyInheritedProperties}.</p>
645      *
646      * @param other the project to copy the properties to. Must not be null.
647      *
648      * @since Ant 1.5
649      */

650     public void copyUserProperties(Project other) {
651         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
652         ph.copyUserProperties(other);
653     }
654
655     /**
656      * Copy all user properties that have not been set on the
657      * command line or a GUI tool from this instance to the Project
658      * instance given as the argument.
659      *
660      * <p>To copy all &quot;user&quot; properties, you will also have to call
661      * {@link #copyUserProperties copyUserProperties}.</p>
662      *
663      * @param other the project to copy the properties to. Must not be null.
664      *
665      * @since Ant 1.5
666      */

667     public void copyInheritedProperties(Project other) {
668         PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
669         ph.copyInheritedProperties(other);
670     }
671
672     /**
673      * Set the default target of the project.
674      *
675      * @param defaultTarget The name of the default target for this project.
676      * May be <code>null</code>, indicating that there is
677      * no default target.
678      *
679      * @deprecated since 1.5.x.
680      * Use setDefault.
681      * @see #setDefault(String)
682      */

683     public void setDefaultTarget(String JavaDoc defaultTarget) {
684         this.defaultTarget = defaultTarget;
685     }
686
687     /**
688      * Return the name of the default target of the project.
689      * @return name of the default target or
690      * <code>null</code> if no default has been set.
691      */

692     public String JavaDoc getDefaultTarget() {
693         return defaultTarget;
694     }
695
696     /**
697      * Set the default target of the project.
698      *
699      * @param defaultTarget The name of the default target for this project.
700      * May be <code>null</code>, indicating that there is
701      * no default target.
702      */

703     public void setDefault(String JavaDoc defaultTarget) {
704         this.defaultTarget = defaultTarget;
705     }
706
707     /**
708      * Set the name of the project, also setting the user
709      * property <code>ant.project.name</code>.
710      *
711      * @param name The name of the project.
712      * Must not be <code>null</code>.
713      */

714     public void setName(String JavaDoc name) {
715         setUserProperty("ant.project.name", name);
716         this.name = name;
717     }
718
719     /**
720      * Return the project name, if one has been set.
721      *
722      * @return the project name, or <code>null</code> if it hasn't been set.
723      */

724     public String JavaDoc getName() {
725         return name;
726     }
727
728     /**
729      * Set the project description.
730      *
731      * @param description The description of the project.
732      * May be <code>null</code>.
733      */

734     public void setDescription(String JavaDoc description) {
735         this.description = description;
736     }
737
738     /**
739      * Return the project description, if one has been set.
740      *
741      * @return the project description, or <code>null</code> if it hasn't
742      * been set.
743      */

744     public String JavaDoc getDescription() {
745         if (description == null) {
746             description = Description.getDescription(this);
747         }
748         return description;
749     }
750
751     /**
752      * Add a filter to the set of global filters.
753      *
754      * @param token The token to filter.
755      * Must not be <code>null</code>.
756      * @param value The replacement value.
757      * Must not be <code>null</code>.
758      * @deprecated since 1.4.x.
759      * Use getGlobalFilterSet().addFilter(token,value)
760      *
761      * @see #getGlobalFilterSet()
762      * @see FilterSet#addFilter(String,String)
763      */

764     public void addFilter(String JavaDoc token, String JavaDoc value) {
765         if (token == null) {
766             return;
767         }
768         globalFilterSet.addFilter(new FilterSet.Filter(token, value));
769     }
770
771     /**
772      * Return a hashtable of global filters, mapping tokens to values.
773      *
774      * @return a hashtable of global filters, mapping tokens to values
775      * (String to String).
776      *
777      * @deprecated since 1.4.x
778      * Use getGlobalFilterSet().getFilterHash().
779      *
780      * @see #getGlobalFilterSet()
781      * @see FilterSet#getFilterHash()
782      */

783     public Hashtable JavaDoc getFilters() {
784         // we need to build the hashtable dynamically
785
return globalFilterSet.getFilterHash();
786     }
787
788     /**
789      * Set the base directory for the project, checking that
790      * the given filename exists and is a directory.
791      *
792      * @param baseD The project base directory.
793      * Must not be <code>null</code>.
794      *
795      * @exception BuildException if the directory if invalid.
796      */

797     public void setBasedir(String JavaDoc baseD) throws BuildException {
798         setBaseDir(new File JavaDoc(baseD));
799     }
800
801     /**
802      * Set the base directory for the project, checking that
803      * the given file exists and is a directory.
804      *
805      * @param baseDir The project base directory.
806      * Must not be <code>null</code>.
807      * @exception BuildException if the specified file doesn't exist or
808      * isn't a directory.
809      */

810     public void setBaseDir(File JavaDoc baseDir) throws BuildException {
811         baseDir = FILE_UTILS.normalize(baseDir.getAbsolutePath());
812         if (!baseDir.exists()) {
813             throw new BuildException("Basedir " + baseDir.getAbsolutePath()
814                 + " does not exist");
815         }
816         if (!baseDir.isDirectory()) {
817             throw new BuildException("Basedir " + baseDir.getAbsolutePath()
818                 + " is not a directory");
819         }
820         this.baseDir = baseDir;
821         setPropertyInternal(MagicNames.PROJECT_BASEDIR, this.baseDir.getPath());
822         String JavaDoc msg = "Project base dir set to: " + this.baseDir;
823          log(msg, MSG_VERBOSE);
824     }
825
826     /**
827      * Return the base directory of the project as a file object.
828      *
829      * @return the project base directory, or <code>null</code> if the
830      * base directory has not been successfully set to a valid value.
831      */

832     public File JavaDoc getBaseDir() {
833         if (baseDir == null) {
834             try {
835                 setBasedir(".");
836             } catch (BuildException ex) {
837                 ex.printStackTrace();
838             }
839         }
840         return baseDir;
841     }
842
843     /**
844      * Set &quot;keep-going&quot; mode. In this mode Ant will try to execute
845      * as many targets as possible. All targets that do not depend
846      * on failed target(s) will be executed. If the keepGoing settor/getter
847      * methods are used in conjunction with the <code>ant.executor.class</code>
848      * property, they will have no effect.
849      * @param keepGoingMode &quot;keep-going&quot; mode
850      * @since Ant 1.6
851      */

852     public void setKeepGoingMode(boolean keepGoingMode) {
853         this.keepGoingMode = keepGoingMode;
854     }
855
856     /**
857      * Return the keep-going mode. If the keepGoing settor/getter
858      * methods are used in conjunction with the <code>ant.executor.class</code>
859      * property, they will have no effect.
860      * @return &quot;keep-going&quot; mode
861      * @since Ant 1.6
862      */

863     public boolean isKeepGoingMode() {
864         return this.keepGoingMode;
865     }
866
867     /**
868      * Return the version of Java this class is running under.
869      * @return the version of Java as a String, e.g. "1.1" .
870      * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
871      * @deprecated since 1.5.x.
872      * Use org.apache.tools.ant.util.JavaEnvUtils instead.
873      */

874     public static String JavaDoc getJavaVersion() {
875         return JavaEnvUtils.getJavaVersion();
876     }
877
878     /**
879      * Set the <code>ant.java.version</code> property and tests for
880      * unsupported JVM versions. If the version is supported,
881      * verbose log messages are generated to record the Java version
882      * and operating system name.
883      *
884      * @exception BuildException if this Java version is not supported.
885      *
886      * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
887      */

888     public void setJavaVersionProperty() throws BuildException {
889         String JavaDoc javaVersion = JavaEnvUtils.getJavaVersion();
890         setPropertyInternal(MagicNames.ANT_JAVA_VERSION, javaVersion);
891
892         // sanity check
893
if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0)
894                 || JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
895             throw new BuildException("Ant cannot work on Java 1.0 / 1.1");
896         }
897         log("Detected Java version: " + javaVersion + " in: "
898             + System.getProperty("java.home"), MSG_VERBOSE);
899
900         log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
901     }
902
903     /**
904      * Add all system properties which aren't already defined as
905      * user properties to the project properties.
906      */

907     public void setSystemProperties() {
908         Properties JavaDoc systemP = System.getProperties();
909         Enumeration JavaDoc e = systemP.propertyNames();
910         while (e.hasMoreElements()) {
911             String JavaDoc propertyName = (String JavaDoc) e.nextElement();
912             String JavaDoc value = systemP.getProperty(propertyName);
913             this.setPropertyInternal(propertyName, value);
914         }
915     }
916
917     /**
918      * Add a new task definition to the project.
919      * Attempting to override an existing definition with an
920      * equivalent one (i.e. with the same classname) results in
921      * a verbose log message. Attempting to override an existing definition
922      * with a different one results in a warning log message and
923      * invalidates any tasks which have already been created with the
924      * old definition.
925      *
926      * @param taskName The name of the task to add.
927      * Must not be <code>null</code>.
928      * @param taskClass The full name of the class implementing the task.
929      * Must not be <code>null</code>.
930      *
931      * @exception BuildException if the class is unsuitable for being an Ant
932      * task. An error level message is logged before
933      * this exception is thrown.
934      *
935      * @see #checkTaskClass(Class)
936      */

937     public void addTaskDefinition(String JavaDoc taskName, Class JavaDoc taskClass)
938          throws BuildException {
939         ComponentHelper.getComponentHelper(this).addTaskDefinition(taskName,
940                 taskClass);
941     }
942
943     /**
944      * Check whether or not a class is suitable for serving as Ant task.
945      * Ant task implementation classes must be public, concrete, and have
946      * a no-arg constructor.
947      *
948      * @param taskClass The class to be checked.
949      * Must not be <code>null</code>.
950      *
951      * @exception BuildException if the class is unsuitable for being an Ant
952      * task. An error level message is logged before
953      * this exception is thrown.
954      */

955     public void checkTaskClass(final Class JavaDoc taskClass) throws BuildException {
956         ComponentHelper.getComponentHelper(this).checkTaskClass(taskClass);
957
958         if (!Modifier.isPublic(taskClass.getModifiers())) {
959             final String JavaDoc message = taskClass + " is not public";
960             log(message, Project.MSG_ERR);
961             throw new BuildException(message);
962         }
963         if (Modifier.isAbstract(taskClass.getModifiers())) {
964             final String JavaDoc message = taskClass + " is abstract";
965             log(message, Project.MSG_ERR);
966             throw new BuildException(message);
967         }
968         try {
969             taskClass.getConstructor((Class JavaDoc[]) null);
970             // don't have to check for public, since
971
// getConstructor finds public constructors only.
972
} catch (NoSuchMethodException JavaDoc e) {
973             final String JavaDoc message = "No public no-arg constructor in "
974                 + taskClass;
975             log(message, Project.MSG_ERR);
976             throw new BuildException(message);
977         } catch (LinkageError JavaDoc e) {
978             String JavaDoc message = "Could not load " + taskClass + ": " + e;
979             log(message, Project.MSG_ERR);
980             throw new BuildException(message, e);
981         }
982         if (!Task.class.isAssignableFrom(taskClass)) {
983             TaskAdapter.checkTaskClass(taskClass, this);
984         }
985     }
986
987     /**
988      * Return the current task definition hashtable. The returned hashtable is
989      * &quot;live&quot; and so should not be modified.
990      *
991      * @return a map of from task name to implementing class
992      * (String to Class).
993      */

994     public Hashtable JavaDoc getTaskDefinitions() {
995         return ComponentHelper.getComponentHelper(this).getTaskDefinitions();
996     }
997
998     /**
999      * Add a new datatype definition.
1000     * Attempting to override an existing definition with an
1001     * equivalent one (i.e. with the same classname) results in
1002     * a verbose log message. Attempting to override an existing definition
1003     * with a different one results in a warning log message, but the
1004     * definition is changed.
1005     *
1006     * @param typeName The name of the datatype.
1007     * Must not be <code>null</code>.
1008     * @param typeClass The full name of the class implementing the datatype.
1009     * Must not be <code>null</code>.
1010     */

1011    public void addDataTypeDefinition(String JavaDoc typeName, Class JavaDoc typeClass) {
1012        ComponentHelper.getComponentHelper(this).addDataTypeDefinition(typeName,
1013                typeClass);
1014    }
1015
1016    /**
1017     * Return the current datatype definition hashtable. The returned
1018     * hashtable is &quot;live&quot; and so should not be modified.
1019     *
1020     * @return a map of from datatype name to implementing class
1021     * (String to Class).
1022     */

1023    public Hashtable JavaDoc getDataTypeDefinitions() {
1024        return ComponentHelper.getComponentHelper(this).getDataTypeDefinitions();
1025    }
1026
1027    /**
1028     * Add a <em>new</em> target to the project.
1029     *
1030     * @param target The target to be added to the project.
1031     * Must not be <code>null</code>.
1032     *
1033     * @exception BuildException if the target already exists in the project
1034     *
1035     * @see Project#addOrReplaceTarget(Target)
1036     */

1037    public void addTarget(Target target) throws BuildException {
1038        addTarget(target.getName(), target);
1039    }
1040
1041    /**
1042     * Add a <em>new</em> target to the project.
1043     *
1044     * @param targetName The name to use for the target.
1045     * Must not be <code>null</code>.
1046     * @param target The target to be added to the project.
1047     * Must not be <code>null</code>.
1048     *
1049     * @exception BuildException if the target already exists in the project.
1050     *
1051     * @see Project#addOrReplaceTarget(String, Target)
1052     */

1053     public void addTarget(String JavaDoc targetName, Target target)
1054         throws BuildException {
1055         if (targets.get(targetName) != null) {
1056             throw new BuildException("Duplicate target: `" + targetName + "'");
1057         }
1058         addOrReplaceTarget(targetName, target);
1059     }
1060
1061    /**
1062     * Add a target to the project, or replaces one with the same
1063     * name.
1064     *
1065     * @param target The target to be added or replaced in the project.
1066     * Must not be <code>null</code>.
1067     */

1068    public void addOrReplaceTarget(Target target) {
1069        addOrReplaceTarget(target.getName(), target);
1070    }
1071
1072    /**
1073     * Add a target to the project, or replaces one with the same
1074     * name.
1075     *
1076     * @param targetName The name to use for the target.
1077     * Must not be <code>null</code>.
1078     * @param target The target to be added or replaced in the project.
1079     * Must not be <code>null</code>.
1080     */

1081    public void addOrReplaceTarget(String JavaDoc targetName, Target target) {
1082        String JavaDoc msg = " +Target: " + targetName;
1083        log(msg, MSG_DEBUG);
1084        target.setProject(this);
1085        targets.put(targetName, target);
1086    }
1087
1088    /**
1089     * Return the hashtable of targets. The returned hashtable
1090     * is &quot;live&quot; and so should not be modified.
1091     * @return a map from name to target (String to Target).
1092     */

1093    public Hashtable JavaDoc getTargets() {
1094        return targets;
1095    }
1096
1097    /**
1098     * Create a new instance of a task, adding it to a list of
1099     * created tasks for later invalidation. This causes all tasks
1100     * to be remembered until the containing project is removed
1101     * @param taskType The name of the task to create an instance of.
1102     * Must not be <code>null</code>.
1103     *
1104     * @return an instance of the specified task, or <code>null</code> if
1105     * the task name is not recognised.
1106     *
1107     * @exception BuildException if the task name is recognised but task
1108     * creation fails.
1109     */

1110    public Task createTask(String JavaDoc taskType) throws BuildException {
1111        return ComponentHelper.getComponentHelper(this).createTask(taskType);
1112    }
1113
1114    /**
1115     * Create a new instance of a data type.
1116     *
1117     * @param typeName The name of the data type to create an instance of.
1118     * Must not be <code>null</code>.
1119     *
1120     * @return an instance of the specified data type, or <code>null</code> if
1121     * the data type name is not recognised.
1122     *
1123     * @exception BuildException if the data type name is recognised but
1124     * instance creation fails.
1125     */

1126    public Object JavaDoc createDataType(String JavaDoc typeName) throws BuildException {
1127        return ComponentHelper.getComponentHelper(this).createDataType(typeName);
1128    }
1129
1130    /**
1131     * Set the Executor instance for this Project.
1132     * @param e the Executor to use.
1133     */

1134    public void setExecutor(Executor e) {
1135        addReference(MagicNames.ANT_EXECUTOR_REFERENCE, e);
1136    }
1137
1138    /**
1139     * Get this Project's Executor (setting it if necessary).
1140     * @return an Executor instance.
1141     */

1142    public Executor getExecutor() {
1143        Object JavaDoc o = getReference(MagicNames.ANT_EXECUTOR_REFERENCE);
1144        if (o == null) {
1145            String JavaDoc classname = getProperty(MagicNames.ANT_EXECUTOR_CLASSNAME);
1146            if (classname == null) {
1147                classname = DefaultExecutor.class.getName();
1148            }
1149            log("Attempting to create object of type " + classname, MSG_DEBUG);
1150            try {
1151                o = Class.forName(classname, true, coreLoader).newInstance();
1152            } catch (ClassNotFoundException JavaDoc seaEnEfEx) {
1153                //try the current classloader
1154
try {
1155                    o = Class.forName(classname).newInstance();
1156                } catch (Exception JavaDoc ex) {
1157                    log(ex.toString(), MSG_ERR);
1158                }
1159            } catch (Exception JavaDoc ex) {
1160                log(ex.toString(), MSG_ERR);
1161            }
1162            if (o == null) {
1163                throw new BuildException(
1164                    "Unable to obtain a Target Executor instance.");
1165            }
1166            setExecutor((Executor) o);
1167        }
1168        return (Executor) o;
1169    }
1170
1171    /**
1172     * Execute the specified sequence of targets, and the targets
1173     * they depend on.
1174     *
1175     * @param names A vector of target name strings to execute.
1176     * Must not be <code>null</code>.
1177     *
1178     * @exception BuildException if the build failed.
1179     */

1180    public void executeTargets(Vector JavaDoc names) throws BuildException {
1181        getExecutor().executeTargets(this,
1182            (String JavaDoc[]) (names.toArray(new String JavaDoc[names.size()])));
1183    }
1184
1185    /**
1186     * Demultiplex output so that each task receives the appropriate
1187     * messages. If the current thread is not currently executing a task,
1188     * the message is logged directly.
1189     *
1190     * @param output Message to handle. Should not be <code>null</code>.
1191     * @param isWarning Whether the text represents an warning (<code>true</code>)
1192     * or information (<code>false</code>).
1193     */

1194    public void demuxOutput(String JavaDoc output, boolean isWarning) {
1195        Task task = getThreadTask(Thread.currentThread());
1196        if (task == null) {
1197            log(output, isWarning ? MSG_WARN : MSG_INFO);
1198        } else {
1199            if (isWarning) {
1200                task.handleErrorOutput(output);
1201            } else {
1202                task.handleOutput(output);
1203            }
1204        }
1205    }
1206
1207    /**
1208     * Read data from the default input stream. If no default has been
1209     * specified, System.in is used.
1210     *
1211     * @param buffer the buffer into which data is to be read.
1212     * @param offset the offset into the buffer at which data is stored.
1213     * @param length the amount of data to read.
1214     *
1215     * @return the number of bytes read.
1216     *
1217     * @exception IOException if the data cannot be read.
1218     * @since Ant 1.6
1219     */

1220    public int defaultInput(byte[] buffer, int offset, int length)
1221        throws IOException JavaDoc {
1222        if (defaultInputStream != null) {
1223            System.out.flush();
1224            return defaultInputStream.read(buffer, offset, length);
1225        } else {
1226            throw new EOFException JavaDoc("No input provided for project");
1227        }
1228    }
1229
1230    /**
1231     * Demux an input request to the correct task.
1232     *
1233     * @param buffer the buffer into which data is to be read.
1234     * @param offset the offset into the buffer at which data is stored.
1235     * @param length the amount of data to read.
1236     *
1237     * @return the number of bytes read.
1238     *
1239     * @exception IOException if the data cannot be read.
1240     * @since Ant 1.6
1241     */

1242    public int demuxInput(byte[] buffer, int offset, int length)
1243        throws IOException JavaDoc {
1244        Task task = getThreadTask(Thread.currentThread());
1245        if (task == null) {
1246            return defaultInput(buffer, offset, length);
1247        } else {
1248            return task.handleInput(buffer, offset, length);
1249        }
1250    }
1251
1252    /**
1253     * Demultiplex flush operations so that each task receives the appropriate
1254     * messages. If the current thread is not currently executing a task,
1255     * the message is logged directly.
1256     *
1257     * @since Ant 1.5.2
1258     *
1259     * @param output Message to handle. Should not be <code>null</code>.
1260     * @param isError Whether the text represents an error (<code>true</code>)
1261     * or information (<code>false</code>).
1262     */

1263    public void demuxFlush(String JavaDoc output, boolean isError) {
1264        Task task = getThreadTask(Thread.currentThread());
1265        if (task == null) {
1266            fireMessageLogged(this, output, isError ? MSG_ERR : MSG_INFO);
1267        } else {
1268            if (isError) {
1269                task.handleErrorFlush(output);
1270            } else {
1271                task.handleFlush(output);
1272            }
1273        }
1274    }
1275
1276    /**
1277     * Execute the specified target and any targets it depends on.
1278     *
1279     * @param targetName The name of the target to execute.
1280     * Must not be <code>null</code>.
1281     *
1282     * @exception BuildException if the build failed.
1283     */

1284    public void executeTarget(String JavaDoc targetName) throws BuildException {
1285
1286        // sanity check ourselves, if we've been asked to build nothing
1287
// then we should complain
1288

1289        if (targetName == null) {
1290            String JavaDoc msg = "No target specified";
1291            throw new BuildException(msg);
1292        }
1293
1294        // Sort and run the dependency tree.
1295
// Sorting checks if all the targets (and dependencies)
1296
// exist, and if there is any cycle in the dependency
1297
// graph.
1298
executeSortedTargets(topoSort(targetName, targets, false));
1299    }
1300
1301    /**
1302     * Execute a <code>Vector</code> of sorted targets.
1303     * @param sortedTargets the aforementioned <code>Vector</code>.
1304     * @throws BuildException on error.
1305     */

1306    public void executeSortedTargets(Vector JavaDoc sortedTargets)
1307        throws BuildException {
1308        Set JavaDoc succeededTargets = new HashSet JavaDoc();
1309        BuildException buildException = null; // first build exception
1310
for (Enumeration JavaDoc iter = sortedTargets.elements();
1311             iter.hasMoreElements();) {
1312            Target curtarget = (Target) iter.nextElement();
1313            boolean canExecute = true;
1314            for (Enumeration JavaDoc depIter = curtarget.getDependencies();
1315                 depIter.hasMoreElements();) {
1316                String JavaDoc dependencyName = ((String JavaDoc) depIter.nextElement());
1317                if (!succeededTargets.contains(dependencyName)) {
1318                    canExecute = false;
1319                    log(curtarget,
1320                        "Cannot execute '" + curtarget.getName() + "' - '"
1321                        + dependencyName + "' failed or was not executed.",
1322                        MSG_ERR);
1323                    break;
1324                }
1325            }
1326            if (canExecute) {
1327                Throwable JavaDoc thrownException = null;
1328                try {
1329                    curtarget.performTasks();
1330                    succeededTargets.add(curtarget.getName());
1331                } catch (RuntimeException JavaDoc ex) {
1332                    if (!(keepGoingMode)) {
1333                        throw ex; // throw further
1334
}
1335                    thrownException = ex;
1336                } catch (Throwable JavaDoc ex) {
1337                    if (!(keepGoingMode)) {
1338                        throw new BuildException(ex);
1339                    }
1340                    thrownException = ex;
1341                }
1342                if (thrownException != null) {
1343                    if (thrownException instanceof BuildException) {
1344                        log(curtarget,
1345                            "Target '" + curtarget.getName()
1346                            + "' failed with message '"
1347                            + thrownException.getMessage() + "'.", MSG_ERR);
1348                        // only the first build exception is reported
1349
if (buildException == null) {
1350                            buildException = (BuildException) thrownException;
1351                        }
1352                    } else {
1353                        log(curtarget,
1354                            "Target '" + curtarget.getName()
1355                            + "' failed with message '"
1356                            + thrownException.getMessage() + "'.", MSG_ERR);
1357                        thrownException.printStackTrace(System.err);
1358                        if (buildException == null) {
1359                            buildException =
1360                                new BuildException(thrownException);
1361                        }
1362                    }
1363                }
1364            }
1365        }
1366        if (buildException != null) {
1367            throw buildException;
1368        }
1369    }
1370
1371    /**
1372     * Return the canonical form of a filename.
1373     * <p>
1374     * If the specified file name is relative it is resolved
1375     * with respect to the given root directory.
1376     *
1377     * @param fileName The name of the file to resolve.
1378     * Must not be <code>null</code>.
1379     *
1380     * @param rootDir The directory respective to which relative file names
1381     * are resolved. May be <code>null</code>, in which case
1382     * the current directory is used.
1383     *
1384     * @return the resolved File.
1385     *
1386     * @deprecated since 1.4.x
1387     */

1388    public File JavaDoc resolveFile(String JavaDoc fileName, File JavaDoc rootDir) {
1389        return FILE_UTILS.resolveFile(rootDir, fileName);
1390    }
1391
1392    /**
1393     * Return the canonical form of a filename.
1394     * <p>
1395     * If the specified file name is relative it is resolved
1396     * with respect to the project's base directory.
1397     *
1398     * @param fileName The name of the file to resolve.
1399     * Must not be <code>null</code>.
1400     *
1401     * @return the resolved File.
1402     *
1403     */

1404    public File JavaDoc resolveFile(String JavaDoc fileName) {
1405        return FILE_UTILS.resolveFile(baseDir, fileName);
1406    }
1407
1408    /**
1409     * Translate a path into its native (platform specific) format.
1410     * <p>
1411     * This method uses PathTokenizer to separate the input path
1412     * into its components. This handles DOS style paths in a relatively
1413     * sensible way. The file separators are then converted to their platform
1414     * specific versions.
1415     *
1416     * @param toProcess The path to be translated.
1417     * May be <code>null</code>.
1418     *
1419     * @return the native version of the specified path or
1420     * an empty string if the path is <code>null</code> or empty.
1421     *
1422     * @deprecated since 1.7
1423     * Use FileUtils.translatePath instead.
1424     *
1425     * @see PathTokenizer
1426     */

1427    public static String JavaDoc translatePath(String JavaDoc toProcess) {
1428        return FileUtils.translatePath(toProcess);
1429    }
1430
1431    /**
1432     * Convenience method to copy a file from a source to a destination.
1433     * No filtering is performed.
1434     *
1435     * @param sourceFile Name of file to copy from.
1436     * Must not be <code>null</code>.
1437     * @param destFile Name of file to copy to.
1438     * Must not be <code>null</code>.
1439     *
1440     * @exception IOException if the copying fails.
1441     *
1442     * @deprecated since 1.4.x
1443     */

1444    public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile)
1445          throws IOException JavaDoc {
1446        FILE_UTILS.copyFile(sourceFile, destFile);
1447    }
1448
1449    /**
1450     * Convenience method to copy a file from a source to a destination
1451     * specifying if token filtering should be used.
1452     *
1453     * @param sourceFile Name of file to copy from.
1454     * Must not be <code>null</code>.
1455     * @param destFile Name of file to copy to.
1456     * Must not be <code>null</code>.
1457     * @param filtering Whether or not token filtering should be used during
1458     * the copy.
1459     *
1460     * @exception IOException if the copying fails.
1461     *
1462     * @deprecated since 1.4.x
1463     */

1464    public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile, boolean filtering)
1465        throws IOException JavaDoc {
1466        FILE_UTILS.copyFile(sourceFile, destFile,
1467            filtering ? globalFilters : null);
1468    }
1469
1470    /**
1471     * Convenience method to copy a file from a source to a
1472     * destination specifying if token filtering should be used and if
1473     * source files may overwrite newer destination files.
1474     *
1475     * @param sourceFile Name of file to copy from.
1476     * Must not be <code>null</code>.
1477     * @param destFile Name of file to copy to.
1478     * Must not be <code>null</code>.
1479     * @param filtering Whether or not token filtering should be used during
1480     * the copy.
1481     * @param overwrite Whether or not the destination file should be
1482     * overwritten if it already exists.
1483     *
1484     * @exception IOException if the copying fails.
1485     *
1486     * @deprecated since 1.4.x
1487     */

1488    public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile, boolean filtering,
1489                         boolean overwrite) throws IOException JavaDoc {
1490        FILE_UTILS.copyFile(sourceFile, destFile,
1491            filtering ? globalFilters : null, overwrite);
1492    }
1493
1494    /**
1495     * Convenience method to copy a file from a source to a
1496     * destination specifying if token filtering should be used, if
1497     * source files may overwrite newer destination files, and if the
1498     * last modified time of the resulting file should be set to
1499     * that of the source file.
1500     *
1501     * @param sourceFile Name of file to copy from.
1502     * Must not be <code>null</code>.
1503     * @param destFile Name of file to copy to.
1504     * Must not be <code>null</code>.
1505     * @param filtering Whether or not token filtering should be used during
1506     * the copy.
1507     * @param overwrite Whether or not the destination file should be
1508     * overwritten if it already exists.
1509     * @param preserveLastModified Whether or not the last modified time of
1510     * the resulting file should be set to that
1511     * of the source file.
1512     *
1513     * @exception IOException if the copying fails.
1514     *
1515     * @deprecated since 1.4.x
1516     */

1517    public void copyFile(String JavaDoc sourceFile, String JavaDoc destFile, boolean filtering,
1518                         boolean overwrite, boolean preserveLastModified)
1519        throws IOException JavaDoc {
1520        FILE_UTILS.copyFile(sourceFile, destFile,
1521            filtering ? globalFilters : null, overwrite, preserveLastModified);
1522    }
1523
1524    /**
1525     * Convenience method to copy a file from a source to a destination.
1526     * No filtering is performed.
1527     *
1528     * @param sourceFile File to copy from.
1529     * Must not be <code>null</code>.
1530     * @param destFile File to copy to.
1531     * Must not be <code>null</code>.
1532     *
1533     * @exception IOException if the copying fails.
1534     *
1535     * @deprecated since 1.4.x
1536     */

1537    public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile) throws IOException JavaDoc {
1538        FILE_UTILS.copyFile(sourceFile, destFile);
1539    }
1540
1541    /**
1542     * Convenience method to copy a file from a source to a destination
1543     * specifying if token filtering should be used.
1544     *
1545     * @param sourceFile File to copy from.
1546     * Must not be <code>null</code>.
1547     * @param destFile File to copy to.
1548     * Must not be <code>null</code>.
1549     * @param filtering Whether or not token filtering should be used during
1550     * the copy.
1551     *
1552     * @exception IOException if the copying fails.
1553     *
1554     * @deprecated since 1.4.x
1555     */

1556    public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, boolean filtering)
1557        throws IOException JavaDoc {
1558        FILE_UTILS.copyFile(sourceFile, destFile,
1559            filtering ? globalFilters : null);
1560    }
1561
1562    /**
1563     * Convenience method to copy a file from a source to a
1564     * destination specifying if token filtering should be used and if
1565     * source files may overwrite newer destination files.
1566     *
1567     * @param sourceFile File to copy from.
1568     * Must not be <code>null</code>.
1569     * @param destFile File to copy to.
1570     * Must not be <code>null</code>.
1571     * @param filtering Whether or not token filtering should be used during
1572     * the copy.
1573     * @param overwrite Whether or not the destination file should be
1574     * overwritten if it already exists.
1575     *
1576     * @exception IOException if the file cannot be copied.
1577     *
1578     * @deprecated since 1.4.x
1579     */

1580    public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, boolean filtering,
1581                         boolean overwrite) throws IOException JavaDoc {
1582        FILE_UTILS.copyFile(sourceFile, destFile,
1583            filtering ? globalFilters : null, overwrite);
1584    }
1585
1586    /**
1587     * Convenience method to copy a file from a source to a
1588     * destination specifying if token filtering should be used, if
1589     * source files may overwrite newer destination files, and if the
1590     * last modified time of the resulting file should be set to
1591     * that of the source file.
1592     *
1593     * @param sourceFile File to copy from.
1594     * Must not be <code>null</code>.
1595     * @param destFile File to copy to.
1596     * Must not be <code>null</code>.
1597     * @param filtering Whether or not token filtering should be used during
1598     * the copy.
1599     * @param overwrite Whether or not the destination file should be
1600     * overwritten if it already exists.
1601     * @param preserveLastModified Whether or not the last modified time of
1602     * the resulting file should be set to that
1603     * of the source file.
1604     *
1605     * @exception IOException if the file cannot be copied.
1606     *
1607     * @deprecated since 1.4.x
1608     */

1609    public void copyFile(File JavaDoc sourceFile, File JavaDoc destFile, boolean filtering,
1610                         boolean overwrite, boolean preserveLastModified)
1611        throws IOException JavaDoc {
1612        FILE_UTILS.copyFile(sourceFile, destFile,
1613            filtering ? globalFilters : null, overwrite, preserveLastModified);
1614    }
1615
1616    /**
1617     * Call File.setLastModified(long time) on Java above 1.1, and logs
1618     * a warning on Java 1.1.
1619     *
1620     * @param file The file to set the last modified time on.
1621     * Must not be <code>null</code>.
1622     *
1623     * @param time the required modification time.
1624     *
1625     * @deprecated since 1.4.x
1626     *
1627     * @exception BuildException if the last modified time cannot be set
1628     * despite running on a platform with a version
1629     * above 1.1.
1630     */

1631    public void setFileLastModified(File JavaDoc file, long time)
1632         throws BuildException {
1633        FILE_UTILS.setFileLastModified(file, time);
1634        log("Setting modification time for " + file, MSG_VERBOSE);
1635    }
1636
1637    /**
1638     * Return the boolean equivalent of a string, which is considered
1639     * <code>true</code> if either <code>"on"</code>, <code>"true"</code>,
1640     * or <code>"yes"</code> is found, ignoring case.
1641     *
1642     * @param s The string to convert to a boolean value.
1643     *
1644     * @return <code>true</code> if the given string is <code>"on"</code>,
1645     * <code>"true"</code> or <code>"yes"</code>, or
1646     * <code>false</code> otherwise.
1647     */

1648    public static boolean toBoolean(String JavaDoc s) {
1649        return ("on".equalsIgnoreCase(s)
1650                || "true".equalsIgnoreCase(s)
1651                || "yes".equalsIgnoreCase(s));
1652    }
1653
1654    /**
1655     * Topologically sort a set of targets. Equivalent to calling
1656     * <code>topoSort(new String[] {root}, targets, true)</code>.
1657     *
1658     * @param root The name of the root target. The sort is created in such
1659     * a way that the sequence of Targets up to the root
1660     * target is the minimum possible such sequence.
1661     * Must not be <code>null</code>.
1662     * @param targetTable A Hashtable mapping names to Targets.
1663     * Must not be <code>null</code>.
1664     * @return a Vector of ALL Target objects in sorted order.
1665     * @exception BuildException if there is a cyclic dependency among the
1666     * targets, or if a named target does not exist.
1667     */

1668    public final Vector JavaDoc topoSort(String JavaDoc root, Hashtable JavaDoc targetTable)
1669        throws BuildException {
1670        return topoSort(new String JavaDoc[] {root}, targetTable, true);
1671    }
1672
1673    /**
1674     * Topologically sort a set of targets. Equivalent to calling
1675     * <code>topoSort(new String[] {root}, targets, returnAll)</code>.
1676     *
1677     * @param root The name of the root target. The sort is created in such
1678     * a way that the sequence of Targets up to the root
1679     * target is the minimum possible such sequence.
1680     * Must not be <code>null</code>.
1681     * @param targetTable A Hashtable mapping names to Targets.
1682     * Must not be <code>null</code>.
1683     * @param returnAll <code>boolean</code> indicating whether to return all
1684     * targets, or the execution sequence only.
1685     * @return a Vector of Target objects in sorted order.
1686     * @exception BuildException if there is a cyclic dependency among the
1687     * targets, or if a named target does not exist.
1688     * @since Ant 1.6.3
1689     */

1690    public final Vector JavaDoc topoSort(String JavaDoc root, Hashtable JavaDoc targetTable,
1691                                 boolean returnAll) throws BuildException {
1692        return topoSort(new String JavaDoc[] {root}, targetTable, returnAll);
1693    }
1694
1695    /**
1696     * Topologically sort a set of targets.
1697     *
1698     * @param root <code>String[]</code> containing the names of the root targets.
1699     * The sort is created in such a way that the ordered sequence of
1700     * Targets is the minimum possible such sequence to the specified
1701     * root targets.
1702     * Must not be <code>null</code>.
1703     * @param targetTable A map of names to targets (String to Target).
1704     * Must not be <code>null</code>.
1705     * @param returnAll <code>boolean</code> indicating whether to return all
1706     * targets, or the execution sequence only.
1707     * @return a Vector of Target objects in sorted order.
1708     * @exception BuildException if there is a cyclic dependency among the
1709     * targets, or if a named target does not exist.
1710     * @since Ant 1.6.3
1711     */

1712    public final Vector JavaDoc topoSort(String JavaDoc[] root, Hashtable JavaDoc targetTable,
1713                                 boolean returnAll) throws BuildException {
1714        Vector JavaDoc ret = new Vector JavaDoc();
1715        Hashtable JavaDoc state = new Hashtable JavaDoc();
1716        Stack JavaDoc visiting = new Stack JavaDoc();
1717
1718        // We first run a DFS based sort using each root as a starting node.
1719
// This creates the minimum sequence of Targets to the root node(s).
1720
// We then do a sort on any remaining unVISITED targets.
1721
// This is unnecessary for doing our build, but it catches
1722
// circular dependencies or missing Targets on the entire
1723
// dependency tree, not just on the Targets that depend on the
1724
// build Target.
1725

1726        for (int i = 0; i < root.length; i++) {
1727            String JavaDoc st = (String JavaDoc) (state.get(root[i]));
1728            if (st == null) {
1729                tsort(root[i], targetTable, state, visiting, ret);
1730            } else if (st == VISITING) {
1731                throw new RuntimeException JavaDoc("Unexpected node in visiting state: "
1732                    + root[i]);
1733            }
1734        }
1735        StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Build sequence for target(s)");
1736
1737        for (int j = 0; j < root.length; j++) {
1738            buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\'');
1739        }
1740        buf.append(" is " + ret);
1741        log(buf.toString(), MSG_VERBOSE);
1742
1743        Vector JavaDoc complete = (returnAll) ? ret : new Vector JavaDoc(ret);
1744        for (Enumeration JavaDoc en = targetTable.keys(); en.hasMoreElements();) {
1745            String JavaDoc curTarget = (String JavaDoc) en.nextElement();
1746            String JavaDoc st = (String JavaDoc) state.get(curTarget);
1747            if (st == null) {
1748                tsort(curTarget, targetTable, state, visiting, complete);
1749            } else if (st == VISITING) {
1750                throw new RuntimeException JavaDoc("Unexpected node in visiting state: "
1751                    + curTarget);
1752            }
1753        }
1754        log("Complete build sequence is " + complete, MSG_VERBOSE);
1755        return ret;
1756    }
1757
1758    /**
1759     * Perform a single step in a recursive depth-first-search traversal of
1760     * the target dependency tree.
1761     * <p>
1762     * The current target is first set to the &quot;visiting&quot; state, and
1763     * pushed onto the &quot;visiting&quot; stack.
1764     * <p>
1765     * An exception is then thrown if any child of the current node is in the
1766     * visiting state, as that implies a circular dependency. The exception
1767     * contains details of the cycle, using elements of the &quot;visiting&quot;
1768     * stack.
1769     * <p>
1770     * If any child has not already been &quot;visited&quot;, this method is
1771     * called recursively on it.
1772     * <p>
1773     * The current target is then added to the ordered list of targets. Note
1774     * that this is performed after the children have been visited in order
1775     * to get the correct order. The current target is set to the
1776     * &quot;visited&quot; state.
1777     * <p>
1778     * By the time this method returns, the ordered list contains the sequence
1779     * of targets up to and including the current target.
1780     *
1781     * @param root The current target to inspect.
1782     * Must not be <code>null</code>.
1783     * @param targetTable A mapping from names to targets (String to Target).
1784     * Must not be <code>null</code>.
1785     * @param state A mapping from target names to states (String to String).
1786     * The states in question are &quot;VISITING&quot; and
1787     * &quot;VISITED&quot;. Must not be <code>null</code>.
1788     * @param visiting A stack of targets which are currently being visited.
1789     * Must not be <code>null</code>.
1790     * @param ret The list to add target names to. This will end up
1791     * containing the complete list of dependencies in
1792     * dependency order.
1793     * Must not be <code>null</code>.
1794     *
1795     * @exception BuildException if a non-existent target is specified or if
1796     * a circular dependency is detected.
1797     */

1798    private void tsort(String JavaDoc root, Hashtable JavaDoc targetTable,
1799                             Hashtable JavaDoc state, Stack JavaDoc visiting,
1800                             Vector JavaDoc ret)
1801        throws BuildException {
1802        state.put(root, VISITING);
1803        visiting.push(root);
1804
1805        Target target = (Target) targetTable.get(root);
1806
1807        // Make sure we exist
1808
if (target == null) {
1809            StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Target \"");
1810            sb.append(root);
1811            sb.append("\" does not exist in the project \"");
1812            sb.append(name);
1813            sb.append("\". ");
1814            visiting.pop();
1815            if (!visiting.empty()) {
1816                String JavaDoc parent = (String JavaDoc) visiting.peek();
1817                sb.append("It is used from target \"");
1818                sb.append(parent);
1819                sb.append("\".");
1820            }
1821            throw new BuildException(new String JavaDoc(sb));
1822        }
1823        for (Enumeration JavaDoc en = target.getDependencies(); en.hasMoreElements();) {
1824            String JavaDoc cur = (String JavaDoc) en.nextElement();
1825            String JavaDoc m = (String JavaDoc) state.get(cur);
1826            if (m == null) {
1827                // Not been visited
1828
tsort(cur, targetTable, state, visiting, ret);
1829            } else if (m == VISITING) {
1830                // Currently visiting this node, so have a cycle
1831
throw makeCircularException(cur, visiting);
1832            }
1833        }
1834        String JavaDoc p = (String JavaDoc) visiting.pop();
1835        if (root != p) {
1836            throw new RuntimeException JavaDoc("Unexpected internal error: expected to "
1837                + "pop " + root + " but got " + p);
1838        }
1839        state.put(root, VISITED);
1840        ret.addElement(target);
1841    }
1842
1843    /**
1844     * Build an appropriate exception detailing a specified circular
1845     * dependency.
1846     *
1847     * @param end The dependency to stop at. Must not be <code>null</code>.
1848     * @param stk A stack of dependencies. Must not be <code>null</code>.
1849     *
1850     * @return a BuildException detailing the specified circular dependency.
1851     */

1852    private static BuildException makeCircularException(String JavaDoc end, Stack JavaDoc stk) {
1853        StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Circular dependency: ");
1854        sb.append(end);
1855        String JavaDoc c;
1856        do {
1857            c = (String JavaDoc) stk.pop();
1858            sb.append(" <- ");
1859            sb.append(c);
1860        } while (!c.equals(end));
1861        return new BuildException(new String JavaDoc(sb));
1862    }
1863
1864    /**
1865     * Inherit the id references.
1866     * @param parent the parent project of this project.
1867     */

1868    public void inheritIDReferences(Project parent) {
1869        parentIdProject = parent;
1870    }
1871
1872    /**
1873     * Attempt to resolve an Unknown Reference using the
1874     * parsed id's - for BC.
1875     */

1876    private Object JavaDoc resolveIdReference(String JavaDoc key, Project callerProject) {
1877        UnknownElement origUE = (UnknownElement) idReferences.get(key);
1878        if (origUE == null) {
1879            return parentIdProject == null
1880                ? null
1881                : parentIdProject.resolveIdReference(key, callerProject);
1882        }
1883        callerProject.log(
1884            "Warning: Reference " + key + " has not been set at runtime,"
1885            + " but was found during" + LINE_SEP
1886            + "build file parsing, attempting to resolve."
1887            + " Future versions of Ant may support" + LINE_SEP
1888            + " referencing ids defined in non-executed targets.", MSG_WARN);
1889        UnknownElement copyUE = origUE.copy(callerProject);
1890        copyUE.maybeConfigure();
1891        return copyUE.getRealThing();
1892    }
1893
1894    /**
1895     * Add an id reference.
1896     * Used for broken build files.
1897     * @param id the id to set.
1898     * @param value the value to set it to (Unknown element in this case.
1899     */

1900    public void addIdReference(String JavaDoc id, Object JavaDoc value) {
1901        idReferences.put(id, value);
1902    }
1903
1904    /**
1905     * Add a reference to the project.
1906     *
1907     * @param referenceName The name of the reference. Must not be <code>null</code>.
1908     * @param value The value of the reference.
1909     */

1910    public void addReference(String JavaDoc referenceName, Object JavaDoc value) {
1911        synchronized (references) {
1912            Object JavaDoc old = ((AntRefTable) references).getReal(referenceName);
1913            if (old == value) {
1914                // no warning, this is not changing anything
1915
return;
1916            }
1917            if (old != null && !(old instanceof UnknownElement)) {
1918                log("Overriding previous definition of reference to " + referenceName,
1919                    MSG_VERBOSE);
1920            }
1921            log("Adding reference: " + referenceName, MSG_DEBUG);
1922            references.put(referenceName, value);
1923        }
1924    }
1925
1926    /**
1927     * Return a map of the references in the project (String to Object).
1928     * The returned hashtable is &quot;live&quot; and so must not be modified.
1929     *
1930     * @return a map of the references in the project (String to Object).
1931     */

1932    public Hashtable JavaDoc getReferences() {
1933        return references;
1934    }
1935
1936    /**
1937     * Look up a reference by its key (ID).
1938     *
1939     * @param key The key for the desired reference.
1940     * Must not be <code>null</code>.
1941     *
1942     * @return the reference with the specified ID, or <code>null</code> if
1943     * there is no such reference in the project.
1944     */

1945    public Object JavaDoc getReference(String JavaDoc key) {
1946        Object JavaDoc ret = references.get(key);
1947        if (ret != null) {
1948            return ret;
1949        }
1950        // Check for old id behaviour
1951
ret = resolveIdReference(key, this);
1952        if (ret == null && !key.equals(MagicNames.REFID_PROPERTY_HELPER)) {
1953            Vector JavaDoc p = new Vector JavaDoc();
1954            PropertyHelper.getPropertyHelper(this).parsePropertyString(
1955                key, new Vector JavaDoc(), p);
1956            if (p.size() == 1) {
1957                log("Unresolvable reference " + key
1958                    + " might be a misuse of property expansion syntax.",
1959                    MSG_WARN);
1960            }
1961        }
1962        return ret;
1963    }
1964
1965    /**
1966     * Return a description of the type of the given element, with
1967     * special handling for instances of tasks and data types.
1968     * <p>
1969     * This is useful for logging purposes.
1970     *
1971     * @param element The element to describe.
1972     * Must not be <code>null</code>.
1973     *
1974     * @return a description of the element type.
1975     *
1976     * @since 1.95, Ant 1.5
1977     */

1978    public String JavaDoc getElementName(Object JavaDoc element) {
1979        return ComponentHelper.getComponentHelper(this).getElementName(element);
1980    }
1981
1982    /**
1983     * Send a &quot;build started&quot; event
1984     * to the build listeners for this project.
1985     */

1986    public void fireBuildStarted() {
1987        BuildEvent event = new BuildEvent(this);
1988        Iterator JavaDoc iter = listeners.iterator();
1989        while (iter.hasNext()) {
1990            BuildListener listener = (BuildListener) iter.next();
1991            listener.buildStarted(event);
1992        }
1993    }
1994
1995    /**
1996     * Send a &quot;build finished&quot; event to the build listeners
1997     * for this project.
1998     * @param exception an exception indicating a reason for a build
1999     * failure. May be <code>null</code>, indicating
2000     * a successful build.
2001     */

2002    public void fireBuildFinished(Throwable JavaDoc exception) {
2003        BuildEvent event = new BuildEvent(this);
2004        event.setException(exception);
2005        Iterator JavaDoc iter = listeners.iterator();
2006        while (iter.hasNext()) {
2007            BuildListener listener = (BuildListener) iter.next();
2008            listener.buildFinished(event);
2009        }
2010        // Inform IH to clear the cache
2011
IntrospectionHelper.clearCache();
2012    }
2013
2014    /**
2015     * Send a &quot;subbuild started&quot; event to the build listeners for
2016     * this project.
2017     *
2018     * @since Ant 1.6.2
2019     */

2020    public void fireSubBuildStarted() {
2021        BuildEvent event = new BuildEvent(this);
2022        Iterator JavaDoc iter = listeners.iterator();
2023        while (iter.hasNext()) {
2024            Object JavaDoc listener = iter.next();
2025            if (listener instanceof SubBuildListener) {
2026                ((SubBuildListener) listener).subBuildStarted(event);
2027            }
2028        }
2029    }
2030
2031    /**
2032     * Send a &quot;subbuild finished&quot; event to the build listeners for
2033     * this project.
2034     * @param exception an exception indicating a reason for a build
2035     * failure. May be <code>null</code>, indicating
2036     * a successful build.
2037     *
2038     * @since Ant 1.6.2
2039     */

2040    public void fireSubBuildFinished(Throwable JavaDoc exception) {
2041        BuildEvent event = new BuildEvent(this);
2042        event.setException(exception);
2043        Iterator JavaDoc iter = listeners.iterator();
2044        while (iter.hasNext()) {
2045            Object JavaDoc listener = iter.next();
2046            if (listener instanceof SubBuildListener) {
2047                ((SubBuildListener) listener).subBuildFinished(event);
2048            }
2049        }
2050    }
2051
2052    /**
2053     * Send a &quot;target started&quot; event to the build listeners
2054     * for this project.
2055     *
2056     * @param target The target which is starting to build.
2057     * Must not be <code>null</code>.
2058     */

2059    protected void fireTargetStarted(Target target) {
2060        BuildEvent event = new BuildEvent(target);
2061        Iterator JavaDoc iter = listeners.iterator();
2062        while (iter.hasNext()) {
2063            BuildListener listener = (BuildListener) iter.next();
2064            listener.targetStarted(event);
2065        }
2066    }
2067
2068    /**
2069     * Send a &quot;target finished&quot; event to the build listeners
2070     * for this project.
2071     *
2072     * @param target The target which has finished building.
2073     * Must not be <code>null</code>.
2074     * @param exception an exception indicating a reason for a build
2075     * failure. May be <code>null</code>, indicating
2076     * a successful build.
2077     */

2078    protected void fireTargetFinished(Target target, Throwable JavaDoc exception) {
2079        BuildEvent event = new BuildEvent(target);
2080        event.setException(exception);
2081        Iterator JavaDoc iter = listeners.iterator();
2082        while (iter.hasNext()) {
2083            BuildListener listener = (BuildListener) iter.next();
2084            listener.targetFinished(event);
2085        }
2086    }
2087
2088    /**
2089     * Send a &quot;task started&quot; event to the build listeners
2090     * for this project.
2091     *
2092     * @param task The target which is starting to execute.
2093     * Must not be <code>null</code>.
2094     */

2095    protected void fireTaskStarted(Task task) {
2096        // register this as the current task on the current thread.
2097
registerThreadTask(Thread.currentThread(), task);
2098        BuildEvent event = new BuildEvent(task);
2099        Iterator JavaDoc iter = listeners.iterator();
2100        while (iter.hasNext()) {
2101            BuildListener listener = (BuildListener) iter.next();
2102            listener.taskStarted(event);
2103        }
2104    }
2105
2106    /**
2107     * Send a &quot;task finished&quot; event to the build listeners for this
2108     * project.
2109     *
2110     * @param task The task which has finished executing.
2111     * Must not be <code>null</code>.
2112     * @param exception an exception indicating a reason for a build
2113     * failure. May be <code>null</code>, indicating
2114     * a successful build.
2115     */

2116    protected void fireTaskFinished(Task task, Throwable JavaDoc exception) {
2117        registerThreadTask(Thread.currentThread(), null);
2118        System.out.flush();
2119        System.err.flush();
2120        BuildEvent event = new BuildEvent(task);
2121        event.setException(exception);
2122        Iterator JavaDoc iter = listeners.iterator();
2123        while (iter.hasNext()) {
2124            BuildListener listener = (BuildListener) iter.next();
2125            listener.taskFinished(event);
2126        }
2127    }
2128
2129    /**
2130     * Send a &quot;message logged&quot; event to the build listeners
2131     * for this project.
2132     *
2133     * @param event The event to send. This should be built up with the
2134     * appropriate task/target/project by the caller, so that
2135     * this method can set the message and priority, then send
2136     * the event. Must not be <code>null</code>.
2137     * @param message The message to send. Should not be <code>null</code>.
2138     * @param priority The priority of the message.
2139     */

2140    private void fireMessageLoggedEvent(BuildEvent event, String JavaDoc message,
2141                                        int priority) {
2142
2143        if (message.endsWith(StringUtils.LINE_SEP)) {
2144            int endIndex = message.length() - StringUtils.LINE_SEP.length();
2145            event.setMessage(message.substring(0, endIndex), priority);
2146        } else {
2147            event.setMessage(message, priority);
2148        }
2149        synchronized (this) {
2150            if (loggingMessage) {
2151                /*
2152                 * One of the Listeners has attempted to access
2153                 * System.err or System.out.
2154                 *
2155                 * We used to throw an exception in this case, but
2156                 * sometimes Listeners can't prevent it(like our own
2157                 * Log4jListener which invokes getLogger() which in
2158                 * turn wants to write to the console).
2159                 *
2160                 * @see http://marc.theaimsgroup.com/?t=110538624200006&r=1&w=2
2161                 *
2162                 * We now (Ant 1.7 and 1.6.3) simply swallow the message.
2163                 */

2164                return;
2165            }
2166            try {
2167                loggingMessage = true;
2168                Iterator JavaDoc iter = listeners.iterator();
2169                while (iter.hasNext()) {
2170                    BuildListener listener = (BuildListener) iter.next();
2171                    listener.messageLogged(event);
2172                }
2173            } finally {
2174                loggingMessage = false;
2175            }
2176        }
2177    }
2178
2179    /**
2180     * Send a &quot;message logged&quot; project level event
2181     * to the build listeners for this project.
2182     *
2183     * @param project The project generating the event.
2184     * Should not be <code>null</code>.
2185     * @param message The message to send. Should not be <code>null</code>.
2186     * @param priority The priority of the message.
2187     */

2188    protected void fireMessageLogged(Project project, String JavaDoc message,
2189                                     int priority) {
2190        fireMessageLogged(project, message, null, priority);
2191    }
2192
2193    /**
2194     * Send a &quot;message logged&quot; project level event
2195     * to the build listeners for this project.
2196     *
2197     * @param project The project generating the event.
2198     * Should not be <code>null</code>.
2199     * @param message The message to send. Should not be <code>null</code>.
2200     * @param throwable The exception that caused this message. May be <code>null</code>.
2201     * @param priority The priority of the message.
2202     * @since 1.7
2203     */

2204    protected void fireMessageLogged(Project project, String JavaDoc message,
2205            Throwable JavaDoc throwable, int priority) {
2206        BuildEvent event = new BuildEvent(project);
2207        event.setException(throwable);
2208        fireMessageLoggedEvent(event, message, priority);
2209    }
2210
2211    /**
2212     * Send a &quot;message logged&quot; target level event
2213     * to the build listeners for this project.
2214     *
2215     * @param target The target generating the event.
2216     * Must not be <code>null</code>.
2217     * @param message The message to send. Should not be <code>null</code>.
2218     * @param priority The priority of the message.
2219     */

2220    protected void fireMessageLogged(Target target, String JavaDoc message,
2221                                     int priority) {
2222        fireMessageLogged(target, message, null, priority);
2223    }
2224
2225    /**
2226     * Send a &quot;message logged&quot; target level event
2227     * to the build listeners for this project.
2228     *
2229     * @param target The target generating the event.
2230     * Must not be <code>null</code>.
2231     * @param message The message to send. Should not be <code>null</code>.
2232     * @param throwable The exception that caused this message. May be <code>null</code>.
2233     * @param priority The priority of the message.
2234     * @since 1.7
2235     */

2236    protected void fireMessageLogged(Target target, String JavaDoc message,
2237            Throwable JavaDoc throwable, int priority) {
2238        BuildEvent event = new BuildEvent(target);
2239        event.setException(throwable);
2240        fireMessageLoggedEvent(event, message, priority);
2241    }
2242
2243    /**
2244     * Send a &quot;message logged&quot; task level event
2245     * to the build listeners for this project.
2246     *
2247     * @param task The task generating the event.
2248     * Must not be <code>null</code>.
2249     * @param message The message to send. Should not be <code>null</code>.
2250     * @param priority The priority of the message.
2251     */

2252    protected void fireMessageLogged(Task task, String JavaDoc message, int priority) {
2253        fireMessageLogged(task, message, null, priority);
2254    }
2255
2256    /**
2257     * Send a &quot;message logged&quot; task level event
2258     * to the build listeners for this project.
2259     *
2260     * @param task The task generating the event.
2261     * Must not be <code>null</code>.
2262     * @param message The message to send. Should not be <code>null</code>.
2263     * @param throwable The exception that caused this message. May be <code>null</code>.
2264     * @param priority The priority of the message.
2265     * @since 1.7
2266     */

2267    protected void fireMessageLogged(Task task, String JavaDoc message,
2268            Throwable JavaDoc throwable, int priority) {
2269        BuildEvent event = new BuildEvent(task);
2270        event.setException(throwable);
2271        fireMessageLoggedEvent(event, message, priority);
2272    }
2273
2274    /**
2275     * Register a task as the current task for a thread.
2276     * If the task is null, the thread's entry is removed.
2277     *
2278     * @param thread the thread on which the task is registered.
2279     * @param task the task to be registered.
2280     * @since Ant 1.5
2281     */

2282    public synchronized void registerThreadTask(Thread JavaDoc thread, Task task) {
2283        if (task != null) {
2284            threadTasks.put(thread, task);
2285            threadGroupTasks.put(thread.getThreadGroup(), task);
2286        } else {
2287            threadTasks.remove(thread);
2288            threadGroupTasks.remove(thread.getThreadGroup());
2289        }
2290    }
2291
2292    /**
2293     * Get the current task associated with a thread, if any.
2294     *
2295     * @param thread the thread for which the task is required.
2296     * @return the task which is currently registered for the given thread or
2297     * null if no task is registered.
2298     */

2299    public Task getThreadTask(Thread JavaDoc thread) {
2300        Task task = (Task) threadTasks.get(thread);
2301        if (task == null) {
2302            ThreadGroup JavaDoc group = thread.getThreadGroup();
2303            while (task == null && group != null) {
2304                task = (Task) threadGroupTasks.get(group);
2305                group = group.getParent();
2306            }
2307        }
2308        return task;
2309    }
2310
2311
2312    // Should move to a separate public class - and have API to add
2313
// listeners, etc.
2314
private static class AntRefTable extends Hashtable JavaDoc {
2315
2316        AntRefTable() {
2317            super();
2318        }
2319
2320        /** Returns the unmodified original object.
2321         * This method should be called internally to
2322         * get the &quot;real&quot; object.
2323         * The normal get method will do the replacement
2324         * of UnknownElement (this is similar with the JDNI
2325         * refs behavior).
2326         */

2327        private Object JavaDoc getReal(Object JavaDoc key) {
2328            return super.get(key);
2329        }
2330
2331        /** Get method for the reference table.
2332         * It can be used to hook dynamic references and to modify
2333         * some references on the fly--for example for delayed
2334         * evaluation.
2335         *
2336         * It is important to make sure that the processing that is
2337         * done inside is not calling get indirectly.
2338         *
2339         * @param key lookup key.
2340         * @return mapped value.
2341         */

2342        public Object JavaDoc get(Object JavaDoc key) {
2343            //System.out.println("AntRefTable.get " + key);
2344
Object JavaDoc o = getReal(key);
2345            if (o instanceof UnknownElement) {
2346                // Make sure that
2347
UnknownElement ue = (UnknownElement) o;
2348                ue.maybeConfigure();
2349                o = ue.getRealThing();
2350            }
2351            return o;
2352        }
2353    }
2354
2355    /**
2356     * Set a reference to this Project on the parameterized object.
2357     * Need to set the project before other set/add elements
2358     * are called.
2359     * @param obj the object to invoke setProject(this) on.
2360     */

2361    public final void setProjectReference(final Object JavaDoc obj) {
2362        if (obj instanceof ProjectComponent) {
2363            ((ProjectComponent) obj).setProject(this);
2364            return;
2365        }
2366        try {
2367            Method JavaDoc method =
2368                obj.getClass().getMethod(
2369                    "setProject", new Class JavaDoc[] {Project.class});
2370            if (method != null) {
2371                method.invoke(obj, new Object JavaDoc[] {this});
2372            }
2373        } catch (Throwable JavaDoc e) {
2374            // ignore this if the object does not have
2375
// a set project method or the method
2376
// is private/protected.
2377
}
2378    }
2379
2380    /**
2381     * Resolve the file relative to the project's basedir and return it as a
2382     * FileResource.
2383     * @param name the name of the file to resolve.
2384     * @return the file resource.
2385     * @since Ant 1.7
2386     */

2387    public Resource getResource(String JavaDoc name) {
2388        return new FileResource(getBaseDir(), name);
2389    }
2390}
2391
Popular Tags