You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Project.java 68 KiB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant;
  55. import java.io.File;
  56. import java.io.InputStream;
  57. import java.io.IOException;
  58. import java.util.Hashtable;
  59. import java.util.Vector;
  60. import java.util.Properties;
  61. import java.util.Enumeration;
  62. import java.util.Stack;
  63. import java.lang.reflect.Modifier;
  64. import org.apache.tools.ant.types.FilterSet;
  65. import org.apache.tools.ant.types.FilterSetCollection;
  66. import org.apache.tools.ant.util.FileUtils;
  67. /**
  68. * Central representation of an Ant project. This class defines an
  69. * Ant project with all of its targets, tasks and various other
  70. * properties. It also provides the mechanism to kick off a build using
  71. * a particular target name.
  72. * <p>
  73. * This class also encapsulates methods which allow files to be referred
  74. * to using abstract path names which are translated to native system
  75. * file paths at runtime.
  76. *
  77. * @author duncan@x180.com
  78. *
  79. * @version $Revision$
  80. */
  81. public class Project {
  82. /** Message priority of "error". */
  83. public final static int MSG_ERR = 0;
  84. /** Message priority of "warning". */
  85. public final static int MSG_WARN = 1;
  86. /** Message priority of "information". */
  87. public final static int MSG_INFO = 2;
  88. /** Message priority of "verbose". */
  89. public final static int MSG_VERBOSE = 3;
  90. /** Message priority of "debug". */
  91. public final static int MSG_DEBUG = 4;
  92. /**
  93. * Constant for the "visiting" state, used when
  94. * traversing a DFS of target dependencies.
  95. */
  96. private final static String VISITING = "VISITING";
  97. /**
  98. * Constant for the "visited" state, used when
  99. * traversing a DFS of target dependencies.
  100. */
  101. private final static String VISITED = "VISITED";
  102. /** Version of currently running VM. */
  103. private static String javaVersion;
  104. /** Version constant for Java 1.0 */
  105. public final static String JAVA_1_0 = "1.0";
  106. /** Version constant for Java 1.1 */
  107. public final static String JAVA_1_1 = "1.1";
  108. /** Version constant for Java 1.2 */
  109. public final static String JAVA_1_2 = "1.2";
  110. /** Version constant for Java 1.3 */
  111. public final static String JAVA_1_3 = "1.3";
  112. /** Version constant for Java 1.4 */
  113. public final static String JAVA_1_4 = "1.4";
  114. /** Default filter start token. */
  115. public final static String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
  116. /** Default filter end token. */
  117. public final static String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
  118. /** Name of this project. */
  119. private String name;
  120. /** Description for this project (if any). */
  121. private String description;
  122. /** Project properties map (String to String). */
  123. private Hashtable properties = new Hashtable();
  124. /**
  125. * Map of "user" properties (as created in the Ant task, for example).
  126. * Note that these key/value pairs are also always put into the
  127. * project properties, so only the project properties need to be queried.
  128. * Mapping is String to String.
  129. */
  130. private Hashtable userProperties = new Hashtable();
  131. /** Map of references within the project (paths etc) (String to Object). */
  132. private Hashtable references = new Hashtable();
  133. /** Name of the project's default target. */
  134. private String defaultTarget;
  135. /** Map from data type names to implementing classes (String to Class). */
  136. private Hashtable dataClassDefinitions = new Hashtable();
  137. /** Map from task names to implementing classes (String to Class). */
  138. private Hashtable taskClassDefinitions = new Hashtable();
  139. /**
  140. * Map from task names to vectors of created tasks
  141. * (String to Vector of Task). This is used to invalidate tasks if
  142. * the task definition changes.
  143. */
  144. private Hashtable createdTasks = new Hashtable();
  145. /** Map from target names to targets (String to Target). */
  146. private Hashtable targets = new Hashtable();
  147. /** Set of global filters. */
  148. private FilterSet globalFilterSet = new FilterSet();
  149. /**
  150. * Wrapper around globalFilterSet. This collection only ever
  151. * contains one FilterSet, but the wrapper is needed in order to
  152. * make it easier to use the FileUtils interface.
  153. */
  154. private FilterSetCollection globalFilters = new FilterSetCollection(globalFilterSet);
  155. /** Project base directory. */
  156. private File baseDir;
  157. /** List of listeners to notify of build events. */
  158. private Vector listeners = new Vector();
  159. protected Vector taskFactories = null;
  160. /**
  161. * The Ant core classloader - may be <code>null</code> if using
  162. * parent classloader.
  163. */
  164. private ClassLoader coreLoader = null;
  165. /** Records the latest task to be executed on a thread (Thread to Task). */
  166. private Hashtable threadTasks = new Hashtable();
  167. static {
  168. // Determine the Java version by looking at available classes
  169. // java.lang.CharSequence was introduced in JDK 1.4
  170. // java.lang.StrictMath was introduced in JDK 1.3
  171. // java.lang.ThreadLocal was introduced in JDK 1.2
  172. // java.lang.Void was introduced in JDK 1.1
  173. // Count up version until a NoClassDefFoundError ends the try
  174. try {
  175. javaVersion = JAVA_1_0;
  176. Class.forName("java.lang.Void");
  177. javaVersion = JAVA_1_1;
  178. Class.forName("java.lang.ThreadLocal");
  179. javaVersion = JAVA_1_2;
  180. Class.forName("java.lang.StrictMath");
  181. javaVersion = JAVA_1_3;
  182. Class.forName("java.lang.CharSequence");
  183. javaVersion = JAVA_1_4;
  184. } catch (ClassNotFoundException cnfe) {
  185. // swallow as we've hit the max class version that
  186. // we have
  187. }
  188. }
  189. /** Instance of a utility class to use for file operations. */
  190. private FileUtils fileUtils;
  191. /**
  192. * Creates a new Ant project.
  193. */
  194. public Project() {
  195. fileUtils = FileUtils.newFileUtils();
  196. }
  197. /**
  198. * Initialises the project.
  199. *
  200. * This involves setting the default task definitions and loading the
  201. * system properties.
  202. *
  203. * @exception BuildException if the default task list cannot be loaded
  204. */
  205. public void init() throws BuildException {
  206. setJavaVersionProperty();
  207. String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
  208. try {
  209. Properties props = new Properties();
  210. InputStream in = this.getClass().getResourceAsStream(defs);
  211. if (in == null) {
  212. throw new BuildException("Can't load default task list");
  213. }
  214. props.load(in);
  215. in.close();
  216. Enumeration enum = props.propertyNames();
  217. while (enum.hasMoreElements()) {
  218. String key = (String) enum.nextElement();
  219. String value = props.getProperty(key);
  220. try {
  221. Class taskClass = Class.forName(value);
  222. addTaskDefinition(key, taskClass);
  223. } catch (NoClassDefFoundError ncdfe) {
  224. log("Could not load a dependent class (" + ncdfe.getMessage() + ") for task " + key, MSG_DEBUG);
  225. } catch (ClassNotFoundException cnfe) {
  226. log("Could not load class (" + value + ") for task " + key, MSG_DEBUG);
  227. }
  228. }
  229. } catch (IOException ioe) {
  230. throw new BuildException("Can't load default task list");
  231. }
  232. String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
  233. try{
  234. Properties props = new Properties();
  235. InputStream in = this.getClass().getResourceAsStream(dataDefs);
  236. if (in == null) {
  237. throw new BuildException("Can't load default datatype list");
  238. }
  239. props.load(in);
  240. in.close();
  241. Enumeration enum = props.propertyNames();
  242. while (enum.hasMoreElements()) {
  243. String key = (String) enum.nextElement();
  244. String value = props.getProperty(key);
  245. try {
  246. Class dataClass = Class.forName(value);
  247. addDataTypeDefinition(key, dataClass);
  248. } catch (NoClassDefFoundError ncdfe) {
  249. // ignore...
  250. } catch (ClassNotFoundException cnfe) {
  251. // ignore...
  252. }
  253. }
  254. } catch (IOException ioe) {
  255. throw new BuildException("Can't load default datatype list");
  256. }
  257. setSystemProperties();
  258. }
  259. /**
  260. * Sets the core classloader for the project. If a <code>null</code>
  261. * classloader is specified, the parent classloader should be used.
  262. *
  263. * @param coreLoader The classloader to use for the project.
  264. * May be <code>null</code>.
  265. */
  266. public void setCoreLoader(ClassLoader coreLoader) {
  267. this.coreLoader = coreLoader;
  268. }
  269. /**
  270. * Returns the core classloader to use for this project.
  271. * This may be <code>null</code>, indicating that
  272. * the parent classloader should be used.
  273. *
  274. * @return the core classloader to use for this project.
  275. *
  276. */
  277. public ClassLoader getCoreLoader() {
  278. return coreLoader;
  279. }
  280. /**
  281. * Adds a build listener to the list. This listener will
  282. * be notified of build events for this project.
  283. *
  284. * @param listener The listener to add to the list.
  285. * Must not be <code>null</code>.
  286. */
  287. public void addBuildListener(BuildListener listener) {
  288. listeners.addElement(listener);
  289. }
  290. /**
  291. * Removes a build listener from the list. This listener
  292. * will no longer be notified of build events for this project.
  293. *
  294. * @param listener The listener to remove from the list.
  295. * Should not be <code>null</code>.
  296. */
  297. public void removeBuildListener(BuildListener listener) {
  298. listeners.removeElement(listener);
  299. }
  300. /**
  301. * Returns a list of build listeners for the project. The returned
  302. * vector is "live" and so should not be modified.
  303. *
  304. * @return a list of build listeners for the project
  305. */
  306. public Vector getBuildListeners() {
  307. return listeners;
  308. }
  309. /**
  310. * Writes a message to the log with the default log level
  311. * of MSG_INFO
  312. * @param msg The text to log. Should not be <code>null</code>.
  313. */
  314. public void log(String msg) {
  315. log(msg, MSG_INFO);
  316. }
  317. /**
  318. * Writes a project level message to the log with the given log level.
  319. * @param msg The text to log. Should not be <code>null</code>.
  320. * @param msgLevel The priority level to log at.
  321. */
  322. public void log(String msg, int msgLevel) {
  323. fireMessageLogged(this, msg, msgLevel);
  324. }
  325. /**
  326. * Writes a task level message to the log with the given log level.
  327. * @param task The task to use in the log. Must not be <code>null</code>.
  328. * @param msg The text to log. Should not be <code>null</code>.
  329. * @param msgLevel The priority level to log at.
  330. */
  331. public void log(Task task, String msg, int msgLevel) {
  332. fireMessageLogged(task, msg, msgLevel);
  333. }
  334. /**
  335. * Writes a target level message to the log with the given log level.
  336. * @param target The target to use in the log.
  337. * Must not be <code>null</code>.
  338. * @param msg The text to log. Should not be <code>null</code>.
  339. * @param msgLevel The priority level to log at.
  340. */
  341. public void log(Target target, String msg, int msgLevel) {
  342. fireMessageLogged(target, msg, msgLevel);
  343. }
  344. /**
  345. * Returns the set of global filters.
  346. *
  347. * @return the set of global filters
  348. */
  349. public FilterSet getGlobalFilterSet() {
  350. return globalFilterSet;
  351. }
  352. /**
  353. * Sets a property. Any existing property of the same name
  354. * is overwritten, unless it is a user property.
  355. * @param name The name of property to set.
  356. * Must not be <code>null</code>.
  357. * @param value The new value of the property.
  358. * Must not be <code>null</code>.
  359. */
  360. public void setProperty(String name, String value) {
  361. // command line properties take precedence
  362. if (null != userProperties.get(name)) {
  363. log("Override ignored for user property " + name, MSG_VERBOSE);
  364. return;
  365. }
  366. if (null != properties.get(name)) {
  367. log("Overriding previous definition of property " + name,
  368. MSG_VERBOSE);
  369. }
  370. log("Setting project property: " + name + " -> " +
  371. value, MSG_DEBUG);
  372. properties.put(name, value);
  373. }
  374. /**
  375. * Sets a property if no value currently exists. If the property
  376. * exists already, a message is logged and the method returns with
  377. * no other effect.
  378. *
  379. * @param name The name of property to set.
  380. * Must not be <code>null</code>.
  381. * @param value The new value of the property.
  382. * Must not be <code>null</code>.
  383. * @since 1.5
  384. */
  385. public void setNewProperty(String name, String value) {
  386. if (null != properties.get(name)) {
  387. log("Override ignored for property " + name, MSG_VERBOSE);
  388. return;
  389. }
  390. log("Setting project property: " + name + " -> " +
  391. value, MSG_DEBUG);
  392. properties.put(name, value);
  393. }
  394. /**
  395. * Sets a user property, which cannot be overwritten by
  396. * set/unset property calls. Any previous value is overwritten.
  397. * @param name The name of property to set.
  398. * Must not be <code>null</code>.
  399. * @param value The new value of the property.
  400. * Must not be <code>null</code>.
  401. * @see #setProperty(String,String)
  402. */
  403. public void setUserProperty(String name, String value) {
  404. log("Setting ro project property: " + name + " -> " +
  405. value, MSG_DEBUG);
  406. userProperties.put(name, value);
  407. properties.put(name, value);
  408. }
  409. /**
  410. * Sets a property unless it is already defined as a user property
  411. * (in which case the method returns silently).
  412. */
  413. private void setPropertyInternal(String name, String value) {
  414. if (null != userProperties.get(name)) {
  415. return;
  416. }
  417. properties.put(name, value);
  418. }
  419. /**
  420. * Returns the value of a property, if it is set.
  421. *
  422. * @param name The name of the property.
  423. * May be <code>null</code>, in which case
  424. * the return value is also <code>null</code>.
  425. * @return the property value, or <code>null</code> for no match
  426. * or if a <code>null</code> name is provided.
  427. */
  428. public String getProperty(String name) {
  429. if (name == null) {
  430. return null;
  431. }
  432. String property = (String) properties.get(name);
  433. return property;
  434. }
  435. /**
  436. * Replaces ${} style constructions in the given value with the
  437. * string value of the corresponding data types.
  438. *
  439. * @param value The string to be scanned for property references.
  440. * May be <code>null</code>.
  441. *
  442. * @return the given string with embedded property names replaced
  443. * by values, or <code>null</code> if the given string is
  444. * <code>null</code>.
  445. *
  446. * @exception BuildException if the given value has an unclosed property name,
  447. * e.g. <code>${xxx</code>
  448. */
  449. public String replaceProperties(String value)
  450. throws BuildException {
  451. return ProjectHelper.replaceProperties(this, value, properties);
  452. }
  453. /**
  454. * Returns the value of a user property, if it is set.
  455. *
  456. * @param name The name of the property.
  457. * May be <code>null</code>, in which case
  458. * the return value is also <code>null</code>.
  459. * @return the property value, or <code>null</code> for no match
  460. * or if a <code>null</code> name is provided.
  461. */
  462. public String getUserProperty(String name) {
  463. if (name == null) {
  464. return null;
  465. }
  466. String property = (String) userProperties.get(name);
  467. return property;
  468. }
  469. /**
  470. * Returns a copy of the properties table.
  471. * @return a hashtable containing all properties (including user properties).
  472. */
  473. public Hashtable getProperties() {
  474. Hashtable propertiesCopy = new Hashtable();
  475. Enumeration e = properties.keys();
  476. while (e.hasMoreElements()) {
  477. Object name = e.nextElement();
  478. Object value = properties.get(name);
  479. propertiesCopy.put(name, value);
  480. }
  481. return propertiesCopy;
  482. }
  483. /**
  484. * Returns a copy of the user property hashtable
  485. * @return a hashtable containing just the user properties
  486. */
  487. public Hashtable getUserProperties() {
  488. Hashtable propertiesCopy = new Hashtable();
  489. Enumeration e = userProperties.keys();
  490. while (e.hasMoreElements()) {
  491. Object name = e.nextElement();
  492. Object value = properties.get(name);
  493. propertiesCopy.put(name, value);
  494. }
  495. return propertiesCopy;
  496. }
  497. /**
  498. * Sets the default target of the project.
  499. *
  500. * @param defaultTarget The name of the default target for this project.
  501. * May be <code>null</code>, indicating that there is
  502. * no default target.
  503. *
  504. * @deprecated use setDefault
  505. * @see #setDefault(String)
  506. */
  507. public void setDefaultTarget(String defaultTarget) {
  508. this.defaultTarget = defaultTarget;
  509. }
  510. /**
  511. * Returns the name of the default target of the project.
  512. * @return name of the default target or
  513. * <code>null</code> if no default has been set.
  514. */
  515. public String getDefaultTarget() {
  516. return defaultTarget;
  517. }
  518. /**
  519. * Sets the default target of the project.
  520. *
  521. * @param defaultTarget The name of the default target for this project.
  522. * May be <code>null</code>, indicating that there is
  523. * no default target.
  524. */
  525. public void setDefault(String defaultTarget) {
  526. this.defaultTarget = defaultTarget;
  527. }
  528. /**
  529. * Sets the name of the project, also setting the user
  530. * property <code>ant.project.name</code>.
  531. *
  532. * @param name The name of the project.
  533. * Must not be <code>null</code>.
  534. */
  535. public void setName(String name) {
  536. setUserProperty("ant.project.name", name);
  537. this.name = name;
  538. }
  539. /**
  540. * Returns the project name, if one has been set.
  541. *
  542. * @return the project name, or <code>null</code> if it hasn't been set.
  543. */
  544. public String getName() {
  545. return name;
  546. }
  547. /**
  548. * Sets the project description.
  549. *
  550. * @param description The description of the project.
  551. * May be <code>null</code>.
  552. */
  553. public void setDescription(String description) {
  554. this.description = description;
  555. }
  556. /**
  557. * Returns the project description, if one has been set.
  558. *
  559. * @return the project description, or <code>null</code> if it hasn't
  560. * been set.
  561. */
  562. public String getDescription() {
  563. return description;
  564. }
  565. /**
  566. * Adds a filter to the set of global filters.
  567. *
  568. * @param token The token to filter.
  569. * Must not be <code>null</code>.
  570. * @deprecated Use getGlobalFilterSet().addFilter(token,value)
  571. *
  572. * @see #getGlobalFilterSet()
  573. * @see FilterSet#addFilter(String,String)
  574. */
  575. public void addFilter(String token, String value) {
  576. if (token == null) {
  577. return;
  578. }
  579. globalFilterSet.addFilter(new FilterSet.Filter(token, value));
  580. }
  581. /**
  582. * Returns a hashtable of global filters, mapping tokens to values.
  583. *
  584. * @return a hashtable of global filters, mapping tokens to values
  585. * (String to String).
  586. *
  587. * @deprecated Use getGlobalFilterSet().getFilterHash()
  588. *
  589. * @see #getGlobalFilterSet()
  590. * @see FilterSet#getFilterHash()
  591. */
  592. public Hashtable getFilters() {
  593. // we need to build the hashtable dynamically
  594. return globalFilterSet.getFilterHash();
  595. }
  596. /**
  597. * Sets the base directory for the project, checking that
  598. * the given filename exists and is a directory.
  599. *
  600. * @param baseD The project base directory.
  601. * Must not be <code>null</code>.
  602. *
  603. * @exception BuildException if the directory if invalid
  604. */
  605. public void setBasedir(String baseD) throws BuildException {
  606. setBaseDir(new File(baseD));
  607. }
  608. /**
  609. * Sets the base directory for the project, checking that
  610. * the given file exists and is a directory.
  611. *
  612. * @param baseDir The project base directory.
  613. * Must not be <code>null</code>.
  614. * @exception BuildException if the specified file doesn't exist or
  615. * isn't a directory
  616. */
  617. public void setBaseDir(File baseDir) throws BuildException {
  618. baseDir = fileUtils.normalize(baseDir.getAbsolutePath());
  619. if (!baseDir.exists()) {
  620. throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " does not exist");
  621. }
  622. if (!baseDir.isDirectory()) {
  623. throw new BuildException("Basedir " + baseDir.getAbsolutePath() + " is not a directory");
  624. }
  625. this.baseDir = baseDir;
  626. setPropertyInternal( "basedir", this.baseDir.getPath());
  627. String msg = "Project base dir set to: " + this.baseDir;
  628. log(msg, MSG_VERBOSE);
  629. }
  630. /**
  631. * Returns the base directory of the project as a file object.
  632. *
  633. * @return the project base directory, or <code>null</code> if the
  634. * base directory has not been successfully set to a valid value.
  635. */
  636. public File getBaseDir() {
  637. if (baseDir == null) {
  638. try {
  639. setBasedir(".");
  640. } catch (BuildException ex) {
  641. ex.printStackTrace();
  642. }
  643. }
  644. return baseDir;
  645. }
  646. /**
  647. * Returns the version of Java this class is running under.
  648. * @return the version of Java as a String, e.g. "1.1"
  649. */
  650. public static String getJavaVersion() {
  651. return javaVersion;
  652. }
  653. /**
  654. * Sets the <code>ant.java.version</code> property and tests for
  655. * unsupported JVM versions. If the version is supported,
  656. * verbose log messages are generated to record the Java version
  657. * and operating system name.
  658. *
  659. * @exception BuildException if this Java version is not supported
  660. *
  661. * @see #getJavaVersion()
  662. */
  663. public void setJavaVersionProperty() throws BuildException {
  664. setPropertyInternal("ant.java.version", javaVersion);
  665. // sanity check
  666. if (javaVersion == JAVA_1_0) {
  667. throw new BuildException("Ant cannot work on Java 1.0");
  668. }
  669. log("Detected Java version: " + javaVersion + " in: " + System.getProperty("java.home"), MSG_VERBOSE);
  670. log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
  671. }
  672. /**
  673. * Adds all system properties which aren't already defined as
  674. * user properties to the project properties.
  675. */
  676. public void setSystemProperties() {
  677. Properties systemP = System.getProperties();
  678. Enumeration e = systemP.keys();
  679. while (e.hasMoreElements()) {
  680. Object name = e.nextElement();
  681. String value = systemP.get(name).toString();
  682. this.setPropertyInternal(name.toString(), value);
  683. }
  684. }
  685. /**
  686. * Adds a new task definition to the project.
  687. * Attempting to override an existing definition with an
  688. * equivalent one (i.e. with the same classname) results in
  689. * a verbose log message. Attempting to override an existing definition
  690. * with a different one results in a warning log message and
  691. * invalidates any tasks which have already been created with the
  692. * old definition.
  693. *
  694. * @param taskName The name of the task to add.
  695. * Must not be <code>null</code>.
  696. * @param taskClass The full name of the class implementing the task.
  697. * Must not be <code>null</code>.
  698. *
  699. * @exception BuildException if the class is unsuitable for being an Ant
  700. * task. An error level message is logged before
  701. * this exception is thrown.
  702. *
  703. * @see #checkTaskClass(Class)
  704. */
  705. public void addTaskDefinition(String taskName, Class taskClass) throws BuildException {
  706. Class old = (Class)taskClassDefinitions.get(taskName);
  707. if (null != old) {
  708. if (old.equals(taskClass)) {
  709. log("Ignoring override for task " + taskName
  710. + ", it is already defined by the same class.",
  711. MSG_VERBOSE);
  712. return;
  713. } else {
  714. log("Trying to override old definition of task "+taskName,
  715. MSG_WARN);
  716. invalidateCreatedTasks(taskName);
  717. }
  718. }
  719. String msg = " +User task: " + taskName + " " + taskClass.getName();
  720. log(msg, MSG_DEBUG);
  721. checkTaskClass(taskClass);
  722. taskClassDefinitions.put(taskName, taskClass);
  723. }
  724. /**
  725. * Checks whether or not a class is suitable for serving as Ant task.
  726. * Ant task implementation classes must be public, concrete, and have
  727. * a no-arg constructor.
  728. *
  729. * @exception BuildException if the class is unsuitable for being an Ant
  730. * task. An error level message is logged before
  731. * this exception is thrown.
  732. */
  733. public void checkTaskClass(final Class taskClass) throws BuildException {
  734. if(!Modifier.isPublic(taskClass.getModifiers())) {
  735. final String message = taskClass + " is not public";
  736. log(message, Project.MSG_ERR);
  737. throw new BuildException(message);
  738. }
  739. if(Modifier.isAbstract(taskClass.getModifiers())) {
  740. final String message = taskClass + " is abstract";
  741. log(message, Project.MSG_ERR);
  742. throw new BuildException(message);
  743. }
  744. try {
  745. taskClass.getConstructor( null );
  746. // don't have to check for public, since
  747. // getConstructor finds public constructors only.
  748. } catch(NoSuchMethodException e) {
  749. final String message = "No public no-arg constructor in " + taskClass;
  750. log(message, Project.MSG_ERR);
  751. throw new BuildException(message);
  752. }
  753. if( !Task.class.isAssignableFrom(taskClass) ) {
  754. TaskAdapter.checkTaskClass(taskClass, this);
  755. }
  756. }
  757. /**
  758. * Returns the current task definition hashtable. The returned hashtable is
  759. * "live" and so should not be modified.
  760. *
  761. * @return a map of from task name to implementing class
  762. * (String to Class).
  763. */
  764. public Hashtable getTaskDefinitions() {
  765. return taskClassDefinitions;
  766. }
  767. /**
  768. * Adds a new datatype definition.
  769. * Attempting to override an existing definition with an
  770. * equivalent one (i.e. with the same classname) results in
  771. * a verbose log message. Attempting to override an existing definition
  772. * with a different one results in a warning log message, but the
  773. * definition is changed.
  774. *
  775. * @param typeName The name of the datatype.
  776. * Must not be <code>null</code>.
  777. * @param taskClass The full name of the class implementing the datatype.
  778. * Must not be <code>null</code>.
  779. */
  780. public void addDataTypeDefinition(String typeName, Class typeClass) {
  781. Class old = (Class)dataClassDefinitions.get(typeName);
  782. if (null != old) {
  783. if (old.equals(typeClass)) {
  784. log("Ignoring override for datatype " + typeName
  785. + ", it is already defined by the same class.",
  786. MSG_VERBOSE);
  787. return;
  788. } else {
  789. log("Trying to override old definition of datatype "+typeName,
  790. MSG_WARN);
  791. }
  792. }
  793. String msg = " +User datatype: " + typeName + " " + typeClass.getName();
  794. log(msg, MSG_DEBUG);
  795. dataClassDefinitions.put(typeName, typeClass);
  796. }
  797. /**
  798. * Returns the current datatype definition hashtable. The returned hashtable is
  799. * "live" and so should not be modified.
  800. *
  801. * @return a map of from datatype name to implementing class
  802. * (String to Class).
  803. */
  804. public Hashtable getDataTypeDefinitions() {
  805. return dataClassDefinitions;
  806. }
  807. /**
  808. * Adds a <em>new</em> target to the project.
  809. *
  810. * @param target The target to be added to the project.
  811. * Must not be <code>null</code>.
  812. *
  813. * @exception BuildException if the target already exists in the project
  814. *
  815. * @see Project#addOrReplaceTarget
  816. */
  817. public void addTarget(Target target) {
  818. String name = target.getName();
  819. if (targets.get(name) != null) {
  820. throw new BuildException("Duplicate target: `"+name+"'");
  821. }
  822. addOrReplaceTarget(name, target);
  823. }
  824. /**
  825. * Adds a <em>new</em> target to the project.
  826. *
  827. * @param targetName The name to use for the target.
  828. * Must not be <code>null</code>.
  829. * @param target The target to be added to the project.
  830. * Must not be <code>null</code>.
  831. *
  832. * @exception BuildException if the target already exists in the project
  833. *
  834. * @see Project#addOrReplaceTarget
  835. */
  836. public void addTarget(String targetName, Target target)
  837. throws BuildException {
  838. if (targets.get(targetName) != null) {
  839. throw new BuildException("Duplicate target: `"+targetName+"'");
  840. }
  841. addOrReplaceTarget(targetName, target);
  842. }
  843. /**
  844. * Adds a target to the project, or replaces one with the same
  845. * name.
  846. *
  847. * @param target The target to be added or replaced in the project.
  848. * Must not be <code>null</code>.
  849. */
  850. public void addOrReplaceTarget(Target target) {
  851. addOrReplaceTarget(target.getName(), target);
  852. }
  853. /**
  854. * Adds a target to the project, or replaces one with the same
  855. * name.
  856. *
  857. * @param targetName The name to use for the target.
  858. * Must not be <code>null</code>.
  859. * @param target The target to be added or replaced in the project.
  860. * Must not be <code>null</code>.
  861. */
  862. public void addOrReplaceTarget(String targetName, Target target) {
  863. String msg = " +Target: " + targetName;
  864. log(msg, MSG_DEBUG);
  865. target.setProject(this);
  866. targets.put(targetName, target);
  867. }
  868. /**
  869. * Returns the hashtable of targets. The returned hashtable
  870. * is "live" and so should not be modified.
  871. * @return a map from name to target (String to Target).
  872. */
  873. public Hashtable getTargets() {
  874. return targets;
  875. }
  876. /** Add a task factory, allowing uesr code to create tasks
  877. */
  878. public void addTaskFactory( TaskFactory fact ) {
  879. if( taskFactories==null ) {
  880. taskFactories=new Vector();
  881. }
  882. taskFactories.addElement( fact );
  883. }
  884. /**
  885. * Creates a new instance of a task.
  886. *
  887. * @param taskType The name of the task to create an instance of.
  888. * Must not be <code>null</code>.
  889. *
  890. * @return an instance of the specified task, or <code>null</code> if
  891. * the task name is not recognised.
  892. *
  893. * @exception BuildException if the task name is recognised but task
  894. * creation fails.
  895. */
  896. public Task createTask(String taskType) throws BuildException {
  897. // XXX Deprecate in a future version
  898. return createTask( null, taskType );
  899. }
  900. /**
  901. * create a new task instance
  902. * @param taskType name of the task
  903. * @param ns namespace of the task ( typically the SAX2 namespace )
  904. * @throws BuildException when task creation goes bad
  905. * @return null if the task name is unknown
  906. */
  907. public Task createTask(String ns, String taskType) throws BuildException {
  908. Task task = null;
  909. if( taskFactories!=null ) {
  910. for( int i=0; i<taskFactories.size(); i++ ) {
  911. TaskFactory tfact=(TaskFactory)taskFactories.elementAt(i);
  912. task=tfact.createTask( this, ns, taskType );
  913. if( task!=null ) {
  914. break;
  915. }
  916. }
  917. }
  918. // fallback to default behavior
  919. // XXX This should be refactored in a "Ant14TaskFactory" and
  920. // used only for backward compat.
  921. // XXX This should throw exception if ns!=null
  922. if( task!=null ) {
  923. Class c = (Class) taskClassDefinitions.get(taskType);
  924. if (c == null) {
  925. return null;
  926. }
  927. try {
  928. Object o = c.newInstance();
  929. if( o instanceof Task ) {
  930. task=(Task)o;
  931. } else {
  932. // "Generic" Bean - use the setter pattern
  933. // and an Adapter
  934. TaskAdapter taskA=new TaskAdapter();
  935. taskA.setProxy( o );
  936. task=taskA;
  937. }
  938. } catch (Throwable t) {
  939. String msg = "Could not create task of type: "
  940. + taskType + " due to " + t;
  941. throw new BuildException(msg, t);
  942. }
  943. }
  944. if( task==null ) {
  945. String msg = "Could not create task of type: "
  946. + taskType + " due to " + t;
  947. throw new BuildException(msg, t);
  948. }
  949. task.setProject(this);
  950. task.setTaskType(taskType);
  951. // set default value, can be changed by the user
  952. task.setTaskName(taskType);
  953. String msg = " +Task: " + taskType;
  954. log (msg, MSG_DEBUG);
  955. addCreatedTask(taskType, task);
  956. return task;
  957. }
  958. /**
  959. * Keeps a record of all tasks that have been created so that they
  960. * can be invalidated if a new task definition overrides the current one.
  961. *
  962. * @param type The name of the type of task which has been created.
  963. * Must not be <code>null</code>.
  964. *
  965. * @param task The freshly created task instance.
  966. * Must not be <code>null</code>.
  967. */
  968. private void addCreatedTask(String type, Task task) {
  969. synchronized (createdTasks) {
  970. Vector v = (Vector) createdTasks.get(type);
  971. if (v == null) {
  972. v = new Vector();
  973. createdTasks.put(type, v);
  974. }
  975. v.addElement(task);
  976. }
  977. }
  978. /**
  979. * Mark tasks as invalid which no longer are of the correct type
  980. * for a given taskname.
  981. *
  982. * @param type The name of the type of task to invalidate.
  983. * Must not be <code>null</code>.
  984. */
  985. private void invalidateCreatedTasks(String type) {
  986. synchronized (createdTasks) {
  987. Vector v = (Vector) createdTasks.get(type);
  988. if (v != null) {
  989. Enumeration enum = v.elements();
  990. while (enum.hasMoreElements()) {
  991. Task t = (Task) enum.nextElement();
  992. t.markInvalid();
  993. }
  994. v.removeAllElements();
  995. createdTasks.remove(type);
  996. }
  997. }
  998. }
  999. /**
  1000. * Creates a new instance of a data type.
  1001. *
  1002. * @param taskType The name of the data type to create an instance of.
  1003. * Must not be <code>null</code>.
  1004. *
  1005. * @return an instance of the specified data type, or <code>null</code> if
  1006. * the data type name is not recognised.
  1007. *
  1008. * @exception BuildException if the data type name is recognised but
  1009. * instance creation fails.
  1010. */
  1011. public Object createDataType(String typeName) throws BuildException {
  1012. Class c = (Class) dataClassDefinitions.get(typeName);
  1013. if (c == null) {
  1014. return null;
  1015. }
  1016. try {
  1017. java.lang.reflect.Constructor ctor = null;
  1018. boolean noArg = false;
  1019. // DataType can have a "no arg" constructor or take a single
  1020. // Project argument.
  1021. try {
  1022. ctor = c.getConstructor(new Class[0]);
  1023. noArg = true;
  1024. } catch (NoSuchMethodException nse) {
  1025. ctor = c.getConstructor(new Class[] {Project.class});
  1026. noArg = false;
  1027. }
  1028. Object o = null;
  1029. if (noArg) {
  1030. o = ctor.newInstance(new Object[0]);
  1031. } else {
  1032. o = ctor.newInstance(new Object[] {this});
  1033. }
  1034. if (o instanceof ProjectComponent) {
  1035. ((ProjectComponent)o).setProject(this);
  1036. }
  1037. String msg = " +DataType: " + typeName;
  1038. log (msg, MSG_DEBUG);
  1039. return o;
  1040. } catch (java.lang.reflect.InvocationTargetException ite) {
  1041. Throwable t = ite.getTargetException();
  1042. String msg = "Could not create datatype of type: "
  1043. + typeName + " due to " + t;
  1044. throw new BuildException(msg, t);
  1045. } catch (Throwable t) {
  1046. String msg = "Could not create datatype of type: "
  1047. + typeName + " due to " + t;
  1048. throw new BuildException(msg, t);
  1049. }
  1050. }
  1051. /**
  1052. * Execute the specified sequence of targets, and the targets
  1053. * they depend on.
  1054. *
  1055. * @param targetNames A vector of target name strings to execute.
  1056. * Must not be <code>null</code>.
  1057. *
  1058. * @exception BuildException if the build failed
  1059. */
  1060. public void executeTargets(Vector targetNames) throws BuildException {
  1061. Throwable error = null;
  1062. for (int i = 0; i < targetNames.size(); i++) {
  1063. executeTarget((String)targetNames.elementAt(i));
  1064. }
  1065. }
  1066. /**
  1067. * Demultiplexes output so that each task receives the appropriate
  1068. * messages. If the current thread is not currently executing a task,
  1069. * the message is logged directly.
  1070. *
  1071. * @param line Message to handle. Should not be <code>null</code>.
  1072. * @param isError Whether the text represents an error (<code>true</code>)
  1073. * or information (<code>false</code>).
  1074. */
  1075. public void demuxOutput(String line, boolean isError) {
  1076. Task task = (Task)threadTasks.get(Thread.currentThread());
  1077. if (task == null) {
  1078. fireMessageLogged(this, line, isError ? MSG_ERR : MSG_INFO);
  1079. }
  1080. else {
  1081. if (isError) {
  1082. task.handleErrorOutput(line);
  1083. }
  1084. else {
  1085. task.handleOutput(line);
  1086. }
  1087. }
  1088. }
  1089. /**
  1090. * Executes the specified target and any targets it depends on.
  1091. *
  1092. * @param targetName The name of the target to execute.
  1093. * Must not be <code>null</code>.
  1094. *
  1095. * @exception BuildException if the build failed
  1096. */
  1097. public void executeTarget(String targetName) throws BuildException {
  1098. // sanity check ourselves, if we've been asked to build nothing
  1099. // then we should complain
  1100. if (targetName == null) {
  1101. String msg = "No target specified";
  1102. throw new BuildException(msg);
  1103. }
  1104. // Sort the dependency tree, and run everything from the
  1105. // beginning until we hit our targetName.
  1106. // Sorting checks if all the targets (and dependencies)
  1107. // exist, and if there is any cycle in the dependency
  1108. // graph.
  1109. Vector sortedTargets = topoSort(targetName, targets);
  1110. int curidx = 0;
  1111. Target curtarget;
  1112. do {
  1113. curtarget = (Target) sortedTargets.elementAt(curidx++);
  1114. curtarget.performTasks();
  1115. } while (!curtarget.getName().equals(targetName));
  1116. }
  1117. /**
  1118. * Returns the canonical form of a filename.
  1119. * <p>
  1120. * If the specified file name is relative it is resolved
  1121. * with respect to the given root directory.
  1122. *
  1123. * @param fileName The name of the file to resolve.
  1124. * Must not be <code>null</code>.
  1125. *
  1126. * @param rootDir The directory to resolve relative file names with
  1127. * respect to. May be <code>null</code>, in which case
  1128. * the current directory is used.
  1129. *
  1130. * @deprecated
  1131. */
  1132. public File resolveFile(String fileName, File rootDir) {
  1133. return fileUtils.resolveFile(rootDir, fileName);
  1134. }
  1135. /**
  1136. * Returns the canonical form of a filename.
  1137. * <p>
  1138. * If the specified file name is relative it is resolved
  1139. * with respect to the project's base directory.
  1140. *
  1141. * @param fileName The name of the file to resolve.
  1142. * Must not be <code>null</code>.
  1143. */
  1144. public File resolveFile(String fileName) {
  1145. return fileUtils.resolveFile(baseDir, fileName);
  1146. }
  1147. /**
  1148. * Translates a path into its native (platform specific) format.
  1149. * <p>
  1150. * This method uses PathTokenizer to separate the input path
  1151. * into its components. This handles DOS style paths in a relatively
  1152. * sensible way. The file separators are then converted to their platform
  1153. * specific versions.
  1154. *
  1155. * @param toProcess The path to be translated.
  1156. * May be <code>null</code>.
  1157. *
  1158. * @return the native version of the specified path or
  1159. * an empty string if the path is <code>null</code> or empty.
  1160. *
  1161. * @see PathTokenizer
  1162. */
  1163. public static String translatePath(String toProcess) {
  1164. if ( toProcess == null || toProcess.length() == 0 ) {
  1165. return "";
  1166. }
  1167. StringBuffer path = new StringBuffer(toProcess.length() + 50);
  1168. PathTokenizer tokenizer = new PathTokenizer(toProcess);
  1169. while (tokenizer.hasMoreTokens()) {
  1170. String pathComponent = tokenizer.nextToken();
  1171. pathComponent = pathComponent.replace('/', File.separatorChar);
  1172. pathComponent = pathComponent.replace('\\', File.separatorChar);
  1173. if (path.length() != 0) {
  1174. path.append(File.pathSeparatorChar);
  1175. }
  1176. path.append(pathComponent);
  1177. }
  1178. return path.toString();
  1179. }
  1180. /**
  1181. * Convenience method to copy a file from a source to a destination.
  1182. * No filtering is performed.
  1183. *
  1184. * @param sourceFile Name of file to copy from.
  1185. * Must not be <code>null</code>.
  1186. * @param destFile Name of file to copy to.
  1187. * Must not be <code>null</code>.
  1188. *
  1189. * @exception IOException if the copying fails
  1190. *
  1191. * @deprecated
  1192. */
  1193. public void copyFile(String sourceFile, String destFile) throws IOException {
  1194. fileUtils.copyFile(sourceFile, destFile);
  1195. }
  1196. /**
  1197. * Convenience method to copy a file from a source to a destination
  1198. * specifying if token filtering should be used.
  1199. *
  1200. * @param sourceFile Name of file to copy from.
  1201. * Must not be <code>null</code>.
  1202. * @param destFile Name of file to copy to.
  1203. * Must not be <code>null</code>.
  1204. * @param filtering Whether or not token filtering should be used during
  1205. * the copy.
  1206. *
  1207. * @exception IOException if the copying fails
  1208. *
  1209. * @deprecated
  1210. */
  1211. public void copyFile(String sourceFile, String destFile, boolean filtering)
  1212. throws IOException {
  1213. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null);
  1214. }
  1215. /**
  1216. * Convenience method to copy a file from a source to a
  1217. * destination specifying if token filtering should be used and if
  1218. * source files may overwrite newer destination files.
  1219. *
  1220. * @param sourceFile Name of file to copy from.
  1221. * Must not be <code>null</code>.
  1222. * @param destFile Name of file to copy to.
  1223. * Must not be <code>null</code>.
  1224. * @param filtering Whether or not token filtering should be used during
  1225. * the copy.
  1226. * @param overwrite Whether or not the destination file should be
  1227. * overwritten if it already exists.
  1228. *
  1229. * @exception IOException if the copying fails
  1230. *
  1231. * @deprecated
  1232. */
  1233. public void copyFile(String sourceFile, String destFile, boolean filtering,
  1234. boolean overwrite) throws IOException {
  1235. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite);
  1236. }
  1237. /**
  1238. * Convenience method to copy a file from a source to a
  1239. * destination specifying if token filtering should be used, if
  1240. * source files may overwrite newer destination files, and if the
  1241. * last modified time of the resulting file should be set to
  1242. * that of the source file.
  1243. *
  1244. * @param sourceFile Name of file to copy from.
  1245. * Must not be <code>null</code>.
  1246. * @param destFile Name of file to copy to.
  1247. * Must not be <code>null</code>.
  1248. * @param filtering Whether or not token filtering should be used during
  1249. * the copy.
  1250. * @param overwrite Whether or not the destination file should be
  1251. * overwritten if it already exists.
  1252. * @param preserveLastModified Whether or not the last modified time of
  1253. * the resulting file should be set to that
  1254. * of the source file.
  1255. *
  1256. * @exception IOException if the copying fails
  1257. *
  1258. * @deprecated
  1259. */
  1260. public void copyFile(String sourceFile, String destFile, boolean filtering,
  1261. boolean overwrite, boolean preserveLastModified)
  1262. throws IOException {
  1263. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null,
  1264. overwrite, preserveLastModified);
  1265. }
  1266. /**
  1267. * Convenience method to copy a file from a source to a destination.
  1268. * No filtering is performed.
  1269. *
  1270. * @param sourceFile File to copy from.
  1271. * Must not be <code>null</code>.
  1272. * @param destFile File to copy to.
  1273. * Must not be <code>null</code>.
  1274. *
  1275. * @exception IOException if the copying fails
  1276. *
  1277. * @deprecated
  1278. */
  1279. public void copyFile(File sourceFile, File destFile) throws IOException {
  1280. fileUtils.copyFile(sourceFile, destFile);
  1281. }
  1282. /**
  1283. * Convenience method to copy a file from a source to a destination
  1284. * specifying if token filtering should be used.
  1285. *
  1286. * @param sourceFile File to copy from.
  1287. * Must not be <code>null</code>.
  1288. * @param destFile File to copy to.
  1289. * Must not be <code>null</code>.
  1290. * @param filtering Whether or not token filtering should be used during
  1291. * the copy.
  1292. *
  1293. * @exception IOException if the copying fails
  1294. *
  1295. * @deprecated
  1296. */
  1297. public void copyFile(File sourceFile, File destFile, boolean filtering)
  1298. throws IOException {
  1299. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null);
  1300. }
  1301. /**
  1302. * Convenience method to copy a file from a source to a
  1303. * destination specifying if token filtering should be used and if
  1304. * source files may overwrite newer destination files.
  1305. *
  1306. * @param sourceFile File to copy from.
  1307. * Must not be <code>null</code>.
  1308. * @param destFile File to copy to.
  1309. * Must not be <code>null</code>.
  1310. * @param filtering Whether or not token filtering should be used during
  1311. * the copy.
  1312. * @param overwrite Whether or not the destination file should be
  1313. * overwritten if it already exists.
  1314. *
  1315. * @exception IOException
  1316. *
  1317. * @deprecated
  1318. */
  1319. public void copyFile(File sourceFile, File destFile, boolean filtering,
  1320. boolean overwrite) throws IOException {
  1321. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null, overwrite);
  1322. }
  1323. /**
  1324. * Convenience method to copy a file from a source to a
  1325. * destination specifying if token filtering should be used, if
  1326. * source files may overwrite newer destination files, and if the
  1327. * last modified time of the resulting file should be set to
  1328. * that of the source file.
  1329. *
  1330. * @param sourceFile File to copy from.
  1331. * Must not be <code>null</code>.
  1332. * @param destFile File to copy to.
  1333. * Must not be <code>null</code>.
  1334. * @param filtering Whether or not token filtering should be used during
  1335. * the copy.
  1336. * @param overwrite Whether or not the destination file should be
  1337. * overwritten if it already exists.
  1338. * @param preserveLastModified Whether or not the last modified time of
  1339. * the resulting file should be set to that
  1340. * of the source file.
  1341. *
  1342. * @exception IOException if the copying fails
  1343. *
  1344. * @deprecated
  1345. */
  1346. public void copyFile(File sourceFile, File destFile, boolean filtering,
  1347. boolean overwrite, boolean preserveLastModified)
  1348. throws IOException {
  1349. fileUtils.copyFile(sourceFile, destFile, filtering ? globalFilters : null,
  1350. overwrite, preserveLastModified);
  1351. }
  1352. /**
  1353. * Calls File.setLastModified(long time) on Java above 1.1, and logs
  1354. * a warning on Java 1.1.
  1355. *
  1356. * @param File The file to set the last modified time on.
  1357. * Must not be <code>null</code>.
  1358. *
  1359. * @deprecated
  1360. *
  1361. * @exception BuildException if the last modified time cannot be set
  1362. * despite running on a platform with a version
  1363. * above 1.1.
  1364. */
  1365. public void setFileLastModified(File file, long time) throws BuildException {
  1366. if (getJavaVersion() == JAVA_1_1) {
  1367. log("Cannot change the modification time of " + file
  1368. + " in JDK 1.1", Project.MSG_WARN);
  1369. return;
  1370. }
  1371. fileUtils.setFileLastModified(file, time);
  1372. log("Setting modification time for " + file, MSG_VERBOSE);
  1373. }
  1374. /**
  1375. * Returns the boolean equivalent of a string, which is considered
  1376. * <code>true</code> if either <code>"on"</code>, <code>"true"</code>,
  1377. * or <code>"yes"</code> is found, ignoring case.
  1378. *
  1379. * @param s The string to convert to a boolean value.
  1380. * Must not be <code>null</code>.
  1381. *
  1382. * @return <code>true</code> if the given string is <code>"on"</code>,
  1383. * <code>"true"</code> or <code>"yes"</code>, or
  1384. * <code>false</code> otherwise.
  1385. */
  1386. public static boolean toBoolean(String s) {
  1387. return (s.equalsIgnoreCase("on") ||
  1388. s.equalsIgnoreCase("true") ||
  1389. s.equalsIgnoreCase("yes"));
  1390. }
  1391. /**
  1392. * Topologically sorts a set of targets.
  1393. *
  1394. * @param root The name of the root target. The sort is created in such
  1395. * a way that the sequence of Targets up to the root
  1396. * target is the minimum possible such sequence.
  1397. * Must not be <code>null</code>.
  1398. * @param targets A map of names to targets (String to Target).
  1399. * Must not be <code>null</code>.
  1400. * @return a vector of strings with the names of the targets in
  1401. * sorted order.
  1402. * @exception BuildException if there is a cyclic dependency among the
  1403. * targets, or if a named target does not exist.
  1404. */
  1405. public final Vector topoSort(String root, Hashtable targets)
  1406. throws BuildException {
  1407. Vector ret = new Vector();
  1408. Hashtable state = new Hashtable();
  1409. Stack visiting = new Stack();
  1410. // We first run a DFS based sort using the root as the starting node.
  1411. // This creates the minimum sequence of Targets to the root node.
  1412. // We then do a sort on any remaining unVISITED targets.
  1413. // This is unnecessary for doing our build, but it catches
  1414. // circular dependencies or missing Targets on the entire
  1415. // dependency tree, not just on the Targets that depend on the
  1416. // build Target.
  1417. tsort(root, targets, state, visiting, ret);
  1418. log("Build sequence for target `"+root+"' is "+ret, MSG_VERBOSE);
  1419. for (Enumeration en=targets.keys(); en.hasMoreElements();) {
  1420. String curTarget = (String)(en.nextElement());
  1421. String st = (String) state.get(curTarget);
  1422. if (st == null) {
  1423. tsort(curTarget, targets, state, visiting, ret);
  1424. }
  1425. else if (st == VISITING) {
  1426. throw new RuntimeException("Unexpected node in visiting state: "+curTarget);
  1427. }
  1428. }
  1429. log("Complete build sequence is "+ret, MSG_VERBOSE);
  1430. return ret;
  1431. }
  1432. /**
  1433. * Performs a single step in a recursive depth-first-search traversal of
  1434. * the target dependency tree.
  1435. * <p>
  1436. * The current target is first set to the "visiting" state, and pushed
  1437. * onto the "visiting" stack.
  1438. * <p>
  1439. * An exception is then thrown if any child of the current node is in the
  1440. * visiting state, as that implies a circular dependency. The exception
  1441. * contains details of the cycle, using elements of the "visiting" stack.
  1442. * <p>
  1443. * If any child has not already been "visited", this method is called
  1444. * recursively on it.
  1445. * <p>
  1446. * The current target is then added to the ordered list of targets. Note
  1447. * that this is performed after the children have been visited in order
  1448. * to get the correct order. The current target is set to the "visited"
  1449. * state.
  1450. * <p>
  1451. * By the time this method returns, the ordered list contains the sequence
  1452. * of targets up to and including the current target.
  1453. *
  1454. * @param root The current target to inspect.
  1455. * Must not be <code>null</code>.
  1456. * @param targets A mapping from names to targets (String to Target).
  1457. * Must not be <code>null</code>.
  1458. * @param state A mapping from target names to states
  1459. * (String to String).
  1460. * The states in question are "VISITING" and "VISITED".
  1461. * Must not be <code>null</code>.
  1462. * @param visiting A stack of targets which are currently being visited.
  1463. * Must not be <code>null</code>.
  1464. * @param ret The list to add target names to. This will end up
  1465. * containing the complete list of depenencies in
  1466. * dependency order.
  1467. * Must not be <code>null</code>.
  1468. *
  1469. * @exception BuildException if a non-existent target is specified or if
  1470. * a circular dependency is detected.
  1471. */
  1472. private final void tsort(String root, Hashtable targets,
  1473. Hashtable state, Stack visiting,
  1474. Vector ret)
  1475. throws BuildException {
  1476. state.put(root, VISITING);
  1477. visiting.push(root);
  1478. Target target = (Target)(targets.get(root));
  1479. // Make sure we exist
  1480. if (target == null) {
  1481. StringBuffer sb = new StringBuffer("Target `");
  1482. sb.append(root);
  1483. sb.append("' does not exist in this project. ");
  1484. visiting.pop();
  1485. if (!visiting.empty()) {
  1486. String parent = (String)visiting.peek();
  1487. sb.append("It is used from target `");
  1488. sb.append(parent);
  1489. sb.append("'.");
  1490. }
  1491. throw new BuildException(new String(sb));
  1492. }
  1493. for (Enumeration en=target.getDependencies(); en.hasMoreElements();) {
  1494. String cur = (String) en.nextElement();
  1495. String m=(String)state.get(cur);
  1496. if (m == null) {
  1497. // Not been visited
  1498. tsort(cur, targets, state, visiting, ret);
  1499. }
  1500. else if (m == VISITING) {
  1501. // Currently visiting this node, so have a cycle
  1502. throw makeCircularException(cur, visiting);
  1503. }
  1504. }
  1505. String p = (String) visiting.pop();
  1506. if (root != p) {
  1507. throw new RuntimeException("Unexpected internal error: expected to pop "+root+" but got "+p);
  1508. }
  1509. state.put(root, VISITED);
  1510. ret.addElement(target);
  1511. }
  1512. /**
  1513. * Builds an appropriate exception detailing a specified circular dependency.
  1514. *
  1515. * @param end The dependency to stop at. Must not be <code>null</code>.
  1516. * @param stk A stack of dependencies. Must not be <code>null</code>.
  1517. *
  1518. * @return a BuildException detailing the specified circular dependency.
  1519. */
  1520. private static BuildException makeCircularException(String end, Stack stk) {
  1521. StringBuffer sb = new StringBuffer("Circular dependency: ");
  1522. sb.append(end);
  1523. String c;
  1524. do {
  1525. c = (String)stk.pop();
  1526. sb.append(" <- ");
  1527. sb.append(c);
  1528. } while(!c.equals(end));
  1529. return new BuildException(new String(sb));
  1530. }
  1531. /**
  1532. * Adds a reference to the project.
  1533. *
  1534. * @param name The name of the reference. Must not be <code>null</code>.
  1535. * @param value The value of the reference. Must not be <code>null</code>.
  1536. */
  1537. public void addReference(String name, Object value) {
  1538. if (null != references.get(name)) {
  1539. log("Overriding previous definition of reference to " + name,
  1540. MSG_WARN);
  1541. }
  1542. log("Adding reference: " + name + " -> " + value, MSG_DEBUG);
  1543. references.put(name,value);
  1544. }
  1545. /**
  1546. * Returns a map of the references in the project (String to Object).
  1547. * The returned hashtable is "live" and so should not be modified.
  1548. *
  1549. * @return a map of the references in the project (String to Object).
  1550. */
  1551. public Hashtable getReferences() {
  1552. return references;
  1553. }
  1554. /**
  1555. * Looks up a reference by its key (ID).
  1556. *
  1557. * @param key The key for the desired reference.
  1558. * Must not be <code>null</code>.
  1559. *
  1560. * @return the reference with the specified ID, or <code>null</code> if
  1561. * there is no such reference in the project.
  1562. */
  1563. public Object getReference(String key) {
  1564. return references.get(key);
  1565. }
  1566. /**
  1567. * Returns a description of the type of the given element, with
  1568. * special handling for instances of tasks and data types.
  1569. * <p>
  1570. * This is useful for logging purposes.
  1571. *
  1572. * @param element The element to describe.
  1573. * Must not be <code>null</code>.
  1574. *
  1575. * @return a description of the element type
  1576. *
  1577. * @since 1.95, Ant 1.5
  1578. */
  1579. public String getElementName(Object element) {
  1580. Hashtable elements = taskClassDefinitions;
  1581. Class elementClass = element.getClass();
  1582. String typeName = "task";
  1583. if (!elements.contains(elementClass)) {
  1584. elements = dataClassDefinitions;
  1585. typeName = "data type";
  1586. if (!elements.contains(elementClass)) {
  1587. elements = null;
  1588. }
  1589. }
  1590. if (elements != null) {
  1591. Enumeration e = elements.keys();
  1592. while (e.hasMoreElements()) {
  1593. String name = (String) e.nextElement();
  1594. Class clazz = (Class) elements.get(name);
  1595. if (elementClass.equals(clazz)) {
  1596. return "The <" + name + "> " + typeName;
  1597. }
  1598. }
  1599. }
  1600. return "Class " + elementClass.getName();
  1601. }
  1602. /**
  1603. * Sends a "build started" event to the build listeners for this project.
  1604. */
  1605. protected void fireBuildStarted() {
  1606. BuildEvent event = new BuildEvent(this);
  1607. for (int i = 0; i < listeners.size(); i++) {
  1608. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1609. listener.buildStarted(event);
  1610. }
  1611. }
  1612. /**
  1613. * Sends a "build finished" event to the build listeners for this project.
  1614. * @param exception an exception indicating a reason for a build
  1615. * failure. May be <code>null</code>, indicating
  1616. * a successful build.
  1617. */
  1618. protected void fireBuildFinished(Throwable exception) {
  1619. BuildEvent event = new BuildEvent(this);
  1620. event.setException(exception);
  1621. for (int i = 0; i < listeners.size(); i++) {
  1622. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1623. listener.buildFinished(event);
  1624. }
  1625. }
  1626. /**
  1627. * Sends a "target started" event to the build listeners for this project.
  1628. *
  1629. * @param target The target which is starting to build.
  1630. * Must not be <code>null</code>.
  1631. */
  1632. protected void fireTargetStarted(Target target) {
  1633. BuildEvent event = new BuildEvent(target);
  1634. for (int i = 0; i < listeners.size(); i++) {
  1635. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1636. listener.targetStarted(event);
  1637. }
  1638. }
  1639. /**
  1640. * Sends a "target finished" event to the build listeners for this
  1641. * project.
  1642. *
  1643. * @param target The target which has finished building.
  1644. * Must not be <code>null</code>.
  1645. * @param exception an exception indicating a reason for a build
  1646. * failure. May be <code>null</code>, indicating
  1647. * a successful build.
  1648. */
  1649. protected void fireTargetFinished(Target target, Throwable exception) {
  1650. BuildEvent event = new BuildEvent(target);
  1651. event.setException(exception);
  1652. for (int i = 0; i < listeners.size(); i++) {
  1653. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1654. listener.targetFinished(event);
  1655. }
  1656. }
  1657. /**
  1658. * Sends a "task started" event to the build listeners for this project.
  1659. *
  1660. * @param task The target which is starting to execute.
  1661. * Must not be <code>null</code>.
  1662. */
  1663. protected void fireTaskStarted(Task task) {
  1664. // register this as the current task on the current thread.
  1665. threadTasks.put(Thread.currentThread(), task);
  1666. BuildEvent event = new BuildEvent(task);
  1667. for (int i = 0; i < listeners.size(); i++) {
  1668. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1669. listener.taskStarted(event);
  1670. }
  1671. }
  1672. /**
  1673. * Sends a "task finished" event to the build listeners for this
  1674. * project.
  1675. *
  1676. * @param task The task which has finished executing.
  1677. * Must not be <code>null</code>.
  1678. * @param exception an exception indicating a reason for a build
  1679. * failure. May be <code>null</code>, indicating
  1680. * a successful build.
  1681. */
  1682. protected void fireTaskFinished(Task task, Throwable exception) {
  1683. threadTasks.remove(Thread.currentThread());
  1684. System.out.flush();
  1685. System.err.flush();
  1686. BuildEvent event = new BuildEvent(task);
  1687. event.setException(exception);
  1688. for (int i = 0; i < listeners.size(); i++) {
  1689. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1690. listener.taskFinished(event);
  1691. }
  1692. }
  1693. /**
  1694. * Sends a "message logged" event to the build listeners for this project.
  1695. *
  1696. * @param event The event to send. This should be built up with the
  1697. * appropriate task/target/project by the caller, so that
  1698. * this method can set the message and priority, then send
  1699. * the event. Must not be <code>null</code>.
  1700. * @param message The message to send. Should not be <code>null</code>.
  1701. * @param priority The priority of the message.
  1702. */
  1703. private void fireMessageLoggedEvent(BuildEvent event, String message, int priority) {
  1704. event.setMessage(message, priority);
  1705. for (int i = 0; i < listeners.size(); i++) {
  1706. BuildListener listener = (BuildListener) listeners.elementAt(i);
  1707. listener.messageLogged(event);
  1708. }
  1709. }
  1710. /**
  1711. * Sends a "message logged" project level event to the build listeners for
  1712. * this project.
  1713. *
  1714. * @param project The project generating the event.
  1715. * Should not be <code>null</code>.
  1716. * @param message The message to send. Should not be <code>null</code>.
  1717. * @param priority The priority of the message.
  1718. */
  1719. protected void fireMessageLogged(Project project, String message, int priority) {
  1720. BuildEvent event = new BuildEvent(project);
  1721. fireMessageLoggedEvent(event, message, priority);
  1722. }
  1723. /**
  1724. * Sends a "message logged" target level event to the build listeners for
  1725. * this project.
  1726. *
  1727. * @param target The target generating the event.
  1728. * Must not be <code>null</code>.
  1729. * @param message The message to send. Should not be <code>null</code>.
  1730. * @param priority The priority of the message.
  1731. */
  1732. protected void fireMessageLogged(Target target, String message, int priority) {
  1733. BuildEvent event = new BuildEvent(target);
  1734. fireMessageLoggedEvent(event, message, priority);
  1735. }
  1736. /**
  1737. * Sends a "message logged" task level event to the build listeners for
  1738. * this project.
  1739. *
  1740. * @param task The task generating the event.
  1741. * Must not be <code>null</code>.
  1742. * @param message The message to send. Should not be <code>null</code>.
  1743. * @param priority The priority of the message.
  1744. */
  1745. protected void fireMessageLogged(Task task, String message, int priority) {
  1746. BuildEvent event = new BuildEvent(task);
  1747. fireMessageLoggedEvent(event, message, priority);
  1748. }
  1749. }