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 81 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185
  1. /*
  2. * Copyright 2000-2005 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.io.EOFException;
  21. import java.io.InputStream;
  22. import java.lang.reflect.Method;
  23. import java.lang.reflect.Modifier;
  24. import java.util.Collections;
  25. import java.util.Enumeration;
  26. import java.util.Hashtable;
  27. import java.util.Iterator;
  28. import java.util.Properties;
  29. import java.util.Stack;
  30. import java.util.Vector;
  31. import java.util.Set;
  32. import java.util.HashSet;
  33. import java.util.Map;
  34. import java.util.WeakHashMap;
  35. import org.apache.tools.ant.input.DefaultInputHandler;
  36. import org.apache.tools.ant.input.InputHandler;
  37. import org.apache.tools.ant.helper.DefaultExecutor;
  38. import org.apache.tools.ant.types.FilterSet;
  39. import org.apache.tools.ant.types.FilterSetCollection;
  40. import org.apache.tools.ant.types.Description;
  41. import org.apache.tools.ant.types.Path;
  42. import org.apache.tools.ant.util.FileUtils;
  43. import org.apache.tools.ant.util.JavaEnvUtils;
  44. import org.apache.tools.ant.util.StringUtils;
  45. /**
  46. * Central representation of an Ant project. This class defines an
  47. * Ant project with all of its targets, tasks and various other
  48. * properties. It also provides the mechanism to kick off a build using
  49. * a particular target name.
  50. * <p>
  51. * This class also encapsulates methods which allow files to be referred
  52. * to using abstract path names which are translated to native system
  53. * file paths at runtime.
  54. *
  55. */
  56. public class Project {
  57. /** Message priority of &quot;error&quot;. */
  58. public static final int MSG_ERR = 0;
  59. /** Message priority of &quot;warning&quot;. */
  60. public static final int MSG_WARN = 1;
  61. /** Message priority of &quot;information&quot;. */
  62. public static final int MSG_INFO = 2;
  63. /** Message priority of &quot;verbose&quot;. */
  64. public static final int MSG_VERBOSE = 3;
  65. /** Message priority of &quot;debug&quot;. */
  66. public static final int MSG_DEBUG = 4;
  67. /**
  68. * Constant for the &quot;visiting&quot; state, used when
  69. * traversing a DFS of target dependencies.
  70. */
  71. private static final String VISITING = "VISITING";
  72. /**
  73. * Constant for the &quot;visited&quot; state, used when
  74. * traversing a DFS of target dependencies.
  75. */
  76. private static final String VISITED = "VISITED";
  77. /**
  78. * Version constant for Java 1.0 .
  79. *
  80. * @deprecated Use {@link JavaEnvUtils#JAVA_1_0} instead.
  81. */
  82. public static final String JAVA_1_0 = JavaEnvUtils.JAVA_1_0;
  83. /**
  84. * Version constant for Java 1.1 .
  85. *
  86. * @deprecated Use {@link JavaEnvUtils#JAVA_1_1} instead.
  87. */
  88. public static final String JAVA_1_1 = JavaEnvUtils.JAVA_1_1;
  89. /**
  90. * Version constant for Java 1.2 .
  91. *
  92. * @deprecated Use {@link JavaEnvUtils#JAVA_1_2} instead.
  93. */
  94. public static final String JAVA_1_2 = JavaEnvUtils.JAVA_1_2;
  95. /**
  96. * Version constant for Java 1.3 .
  97. *
  98. * @deprecated Use {@link JavaEnvUtils#JAVA_1_3} instead.
  99. */
  100. public static final String JAVA_1_3 = JavaEnvUtils.JAVA_1_3;
  101. /**
  102. * Version constant for Java 1.4 .
  103. *
  104. * @deprecated Use {@link JavaEnvUtils#JAVA_1_4} instead.
  105. */
  106. public static final String JAVA_1_4 = JavaEnvUtils.JAVA_1_4;
  107. /** Default filter start token. */
  108. public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
  109. /** Default filter end token. */
  110. public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
  111. /** Instance of a utility class to use for file operations. */
  112. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  113. /** Name of this project. */
  114. private String name;
  115. /** Description for this project (if any). */
  116. private String description;
  117. /** Map of references within the project (paths etc) (String to Object). */
  118. private Hashtable references = new AntRefTable();
  119. /** Name of the project's default target. */
  120. private String defaultTarget;
  121. /** Map from target names to targets (String to Target). */
  122. private Hashtable targets = new Hashtable();
  123. /** Set of global filters. */
  124. private FilterSet globalFilterSet = new FilterSet();
  125. {
  126. // Initialize the globalFileSet's project
  127. globalFilterSet.setProject(this);
  128. }
  129. /**
  130. * Wrapper around globalFilterSet. This collection only ever
  131. * contains one FilterSet, but the wrapper is needed in order to
  132. * make it easier to use the FileUtils interface.
  133. */
  134. private FilterSetCollection globalFilters
  135. = new FilterSetCollection(globalFilterSet);
  136. /** Project base directory. */
  137. private File baseDir;
  138. /** List of listeners to notify of build events. */
  139. private Vector listeners = new Vector();
  140. /**
  141. * The Ant core classloader--may be <code>null</code> if using
  142. * parent classloader.
  143. */
  144. private ClassLoader coreLoader = null;
  145. /** Records the latest task to be executed on a thread. */
  146. private Map/*<Thread,Task>*/ threadTasks = Collections.synchronizedMap(new WeakHashMap());
  147. /** Records the latest task to be executed on a thread group. */
  148. private Map/*<ThreadGroup,Task>*/ threadGroupTasks = Collections.synchronizedMap(new WeakHashMap());
  149. /**
  150. * Called to handle any input requests.
  151. */
  152. private InputHandler inputHandler = null;
  153. /**
  154. * The default input stream used to read any input.
  155. */
  156. private InputStream defaultInputStream = null;
  157. /**
  158. * Keep going flag.
  159. */
  160. private boolean keepGoingMode = false;
  161. /**
  162. * Flag which catches Listeners which try to use System.out or System.err .
  163. */
  164. private boolean loggingMessage = false;
  165. /**
  166. * Set the input handler.
  167. *
  168. * @param handler the InputHandler instance to use for gathering input.
  169. */
  170. public void setInputHandler(InputHandler handler) {
  171. inputHandler = handler;
  172. }
  173. /**
  174. * Set the default System input stream. Normally this stream is set to
  175. * System.in. This inputStream is used when no task input redirection is
  176. * being performed.
  177. *
  178. * @param defaultInputStream the default input stream to use when input
  179. * is requested.
  180. * @since Ant 1.6
  181. */
  182. public void setDefaultInputStream(InputStream defaultInputStream) {
  183. this.defaultInputStream = defaultInputStream;
  184. }
  185. /**
  186. * Get this project's input stream.
  187. *
  188. * @return the InputStream instance in use by this Project instance to
  189. * read input.
  190. */
  191. public InputStream getDefaultInputStream() {
  192. return defaultInputStream;
  193. }
  194. /**
  195. * Retrieve the current input handler.
  196. *
  197. * @return the InputHandler instance currently in place for the project
  198. * instance.
  199. */
  200. public InputHandler getInputHandler() {
  201. return inputHandler;
  202. }
  203. /**
  204. * Create a new Ant project.
  205. */
  206. public Project() {
  207. inputHandler = new DefaultInputHandler();
  208. }
  209. /**
  210. * Create and initialize a subproject. By default the subproject will be of
  211. * the same type as its parent. If a no-arg constructor is unavailable, the
  212. * <code>Project</code> class will be used.
  213. * @return a Project instance configured as a subproject of this Project.
  214. * @since Ant 1.7
  215. */
  216. public Project createSubProject() {
  217. Project subProject = null;
  218. try {
  219. subProject = (Project) (getClass().newInstance());
  220. } catch (Exception e) {
  221. subProject = new Project();
  222. }
  223. initSubProject(subProject);
  224. return subProject;
  225. }
  226. /**
  227. * Initialize a subproject.
  228. * @param subProject the subproject to initialize.
  229. */
  230. public void initSubProject(Project subProject) {
  231. ComponentHelper.getComponentHelper(subProject)
  232. .initSubProject(ComponentHelper.getComponentHelper(this));
  233. subProject.setDefaultInputStream(getDefaultInputStream());
  234. subProject.setKeepGoingMode(this.isKeepGoingMode());
  235. subProject.setExecutor(getExecutor().getSubProjectExecutor());
  236. }
  237. /**
  238. * Initialise the project.
  239. *
  240. * This involves setting the default task definitions and loading the
  241. * system properties.
  242. *
  243. * @exception BuildException if the default task list cannot be loaded.
  244. */
  245. public void init() throws BuildException {
  246. setJavaVersionProperty();
  247. ComponentHelper.getComponentHelper(this).initDefaultDefinitions();
  248. setSystemProperties();
  249. }
  250. /**
  251. * Factory method to create a class loader for loading classes from
  252. * a given path.
  253. *
  254. * @param path the path from which classes are to be loaded.
  255. *
  256. * @return an appropriate classloader.
  257. */
  258. public AntClassLoader createClassLoader(Path path) {
  259. AntClassLoader loader = new AntClassLoader();
  260. loader.setProject(this);
  261. loader.setClassPath(path);
  262. return loader;
  263. }
  264. /**
  265. * Set the core classloader for the project. If a <code>null</code>
  266. * classloader is specified, the parent classloader should be used.
  267. *
  268. * @param coreLoader The classloader to use for the project.
  269. * May be <code>null</code>.
  270. */
  271. public void setCoreLoader(ClassLoader coreLoader) {
  272. this.coreLoader = coreLoader;
  273. }
  274. /**
  275. * Return the core classloader to use for this project.
  276. * This may be <code>null</code>, indicating that
  277. * the parent classloader should be used.
  278. *
  279. * @return the core classloader to use for this project.
  280. *
  281. */
  282. public ClassLoader getCoreLoader() {
  283. return coreLoader;
  284. }
  285. /**
  286. * Add a build listener to the list. This listener will
  287. * be notified of build events for this project.
  288. *
  289. * @param listener The listener to add to the list.
  290. * Must not be <code>null</code>.
  291. */
  292. public synchronized void addBuildListener(BuildListener listener) {
  293. // create a new Vector to avoid ConcurrentModificationExc when
  294. // the listeners get added/removed while we are in fire
  295. Vector newListeners = getBuildListeners();
  296. newListeners.addElement(listener);
  297. listeners = newListeners;
  298. }
  299. /**
  300. * Remove a build listener from the list. This listener
  301. * will no longer be notified of build events for this project.
  302. *
  303. * @param listener The listener to remove from the list.
  304. * Should not be <code>null</code>.
  305. */
  306. public synchronized void removeBuildListener(BuildListener listener) {
  307. // create a new Vector to avoid ConcurrentModificationExc when
  308. // the listeners get added/removed while we are in fire
  309. Vector newListeners = getBuildListeners();
  310. newListeners.removeElement(listener);
  311. listeners = newListeners;
  312. }
  313. /**
  314. * Return a copy of the list of build listeners for the project.
  315. *
  316. * @return a list of build listeners for the project
  317. */
  318. public Vector getBuildListeners() {
  319. return (Vector) listeners.clone();
  320. }
  321. /**
  322. * Write a message to the log with the default log level
  323. * of MSG_INFO .
  324. * @param message The text to log. Should not be <code>null</code>.
  325. */
  326. public void log(String message) {
  327. log(message, MSG_INFO);
  328. }
  329. /**
  330. * Write a project level message to the log with the given log level.
  331. * @param message The text to log. Should not be <code>null</code>.
  332. * @param msgLevel The log priority level to use.
  333. */
  334. public void log(String message, int msgLevel) {
  335. fireMessageLogged(this, message, msgLevel);
  336. }
  337. /**
  338. * Write a task level message to the log with the given log level.
  339. * @param task The task to use in the log. Must not be <code>null</code>.
  340. * @param message The text to log. Should not be <code>null</code>.
  341. * @param msgLevel The log priority level to use.
  342. */
  343. public void log(Task task, String message, int msgLevel) {
  344. fireMessageLogged(task, message, msgLevel);
  345. }
  346. /**
  347. * Write a target level message to the log with the given log level.
  348. * @param target The target to use in the log.
  349. * Must not be <code>null</code>.
  350. * @param message The text to log. Should not be <code>null</code>.
  351. * @param msgLevel The log priority level to use.
  352. */
  353. public void log(Target target, String message, int msgLevel) {
  354. fireMessageLogged(target, message, msgLevel);
  355. }
  356. /**
  357. * Return the set of global filters.
  358. *
  359. * @return the set of global filters.
  360. */
  361. public FilterSet getGlobalFilterSet() {
  362. return globalFilterSet;
  363. }
  364. /**
  365. * Set a property. Any existing property of the same name
  366. * is overwritten, unless it is a user property.
  367. * @param name The name of property to set.
  368. * Must not be <code>null</code>.
  369. * @param value The new value of the property.
  370. * Must not be <code>null</code>.
  371. */
  372. public void setProperty(String name, String value) {
  373. PropertyHelper.getPropertyHelper(this).
  374. setProperty(null, name, value, true);
  375. }
  376. /**
  377. * Set a property if no value currently exists. If the property
  378. * exists already, a message is logged and the method returns with
  379. * no other effect.
  380. *
  381. * @param name The name of property to set.
  382. * Must not be <code>null</code>.
  383. * @param value The new value of the property.
  384. * Must not be <code>null</code>.
  385. * @since 1.5
  386. */
  387. public void setNewProperty(String name, String value) {
  388. PropertyHelper.getPropertyHelper(this).setNewProperty(null, name,
  389. value);
  390. }
  391. /**
  392. * Set a user property, which cannot be overwritten by
  393. * set/unset property calls. Any previous value is overwritten.
  394. * @param name The name of property to set.
  395. * Must not be <code>null</code>.
  396. * @param value The new value of the property.
  397. * Must not be <code>null</code>.
  398. * @see #setProperty(String,String)
  399. */
  400. public void setUserProperty(String name, String value) {
  401. PropertyHelper.getPropertyHelper(this).setUserProperty(null, name,
  402. value);
  403. }
  404. /**
  405. * Set a user property, which cannot be overwritten by set/unset
  406. * property calls. Any previous value is overwritten. Also marks
  407. * these properties as properties that have not come from the
  408. * command line.
  409. *
  410. * @param name The name of property to set.
  411. * Must not be <code>null</code>.
  412. * @param value The new value of the property.
  413. * Must not be <code>null</code>.
  414. * @see #setProperty(String,String)
  415. */
  416. public void setInheritedProperty(String name, String value) {
  417. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  418. ph.setInheritedProperty(null, name, value);
  419. }
  420. /**
  421. * Set a property unless it is already defined as a user property
  422. * (in which case the method returns silently).
  423. *
  424. * @param name The name of the property.
  425. * Must not be <code>null</code>.
  426. * @param value The property value. Must not be <code>null</code>.
  427. */
  428. private void setPropertyInternal(String name, String value) {
  429. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  430. ph.setProperty(null, name, value, false);
  431. }
  432. /**
  433. * Return the value of a property, if it is set.
  434. *
  435. * @param propertyName The name of the property.
  436. * May be <code>null</code>, in which case
  437. * the return value is also <code>null</code>.
  438. * @return the property value, or <code>null</code> for no match
  439. * or if a <code>null</code> name is provided.
  440. */
  441. public String getProperty(String propertyName) {
  442. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  443. return (String) ph.getProperty(null, propertyName);
  444. }
  445. /**
  446. * Replace ${} style constructions in the given value with the
  447. * string value of the corresponding data types.
  448. *
  449. * @param value The string to be scanned for property references.
  450. * May be <code>null</code>.
  451. *
  452. * @return the given string with embedded property names replaced
  453. * by values, or <code>null</code> if the given string is
  454. * <code>null</code>.
  455. *
  456. * @exception BuildException if the given value has an unclosed
  457. * property name, e.g. <code>${xxx</code>.
  458. */
  459. public String replaceProperties(String value)
  460. throws BuildException {
  461. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  462. return ph.replaceProperties(null, value, null);
  463. }
  464. /**
  465. * Return the value of a user property, if it is set.
  466. *
  467. * @param propertyName The name of the property.
  468. * May be <code>null</code>, in which case
  469. * the return value is also <code>null</code>.
  470. * @return the property value, or <code>null</code> for no match
  471. * or if a <code>null</code> name is provided.
  472. */
  473. public String getUserProperty(String propertyName) {
  474. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  475. return (String) ph.getUserProperty(null, propertyName);
  476. }
  477. /**
  478. * Return a copy of the properties table.
  479. * @return a hashtable containing all properties
  480. * (including user properties).
  481. */
  482. public Hashtable getProperties() {
  483. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  484. return ph.getProperties();
  485. }
  486. /**
  487. * Return a copy of the user property hashtable.
  488. * @return a hashtable containing just the user properties.
  489. */
  490. public Hashtable getUserProperties() {
  491. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  492. return ph.getUserProperties();
  493. }
  494. /**
  495. * Copy all user properties that have been set on the command
  496. * line or a GUI tool from this instance to the Project instance
  497. * given as the argument.
  498. *
  499. * <p>To copy all &quot;user&quot; properties, you will also have to call
  500. * {@link #copyInheritedProperties copyInheritedProperties}.</p>
  501. *
  502. * @param other the project to copy the properties to. Must not be null.
  503. *
  504. * @since Ant 1.5
  505. */
  506. public void copyUserProperties(Project other) {
  507. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  508. ph.copyUserProperties(other);
  509. }
  510. /**
  511. * Copy all user properties that have not been set on the
  512. * command line or a GUI tool from this instance to the Project
  513. * instance given as the argument.
  514. *
  515. * <p>To copy all &quot;user&quot; properties, you will also have to call
  516. * {@link #copyUserProperties copyUserProperties}.</p>
  517. *
  518. * @param other the project to copy the properties to. Must not be null.
  519. *
  520. * @since Ant 1.5
  521. */
  522. public void copyInheritedProperties(Project other) {
  523. PropertyHelper ph = PropertyHelper.getPropertyHelper(this);
  524. ph.copyInheritedProperties(other);
  525. }
  526. /**
  527. * Set the default target of the project.
  528. *
  529. * @param defaultTarget The name of the default target for this project.
  530. * May be <code>null</code>, indicating that there is
  531. * no default target.
  532. *
  533. * @deprecated use setDefault
  534. * @see #setDefault(String)
  535. */
  536. public void setDefaultTarget(String defaultTarget) {
  537. this.defaultTarget = defaultTarget;
  538. }
  539. /**
  540. * Return the name of the default target of the project.
  541. * @return name of the default target or
  542. * <code>null</code> if no default has been set.
  543. */
  544. public String getDefaultTarget() {
  545. return defaultTarget;
  546. }
  547. /**
  548. * Set the default target of the project.
  549. *
  550. * @param defaultTarget The name of the default target for this project.
  551. * May be <code>null</code>, indicating that there is
  552. * no default target.
  553. */
  554. public void setDefault(String defaultTarget) {
  555. this.defaultTarget = defaultTarget;
  556. }
  557. /**
  558. * Set the name of the project, also setting the user
  559. * property <code>ant.project.name</code>.
  560. *
  561. * @param name The name of the project.
  562. * Must not be <code>null</code>.
  563. */
  564. public void setName(String name) {
  565. setUserProperty("ant.project.name", name);
  566. this.name = name;
  567. }
  568. /**
  569. * Return the project name, if one has been set.
  570. *
  571. * @return the project name, or <code>null</code> if it hasn't been set.
  572. */
  573. public String getName() {
  574. return name;
  575. }
  576. /**
  577. * Set the project description.
  578. *
  579. * @param description The description of the project.
  580. * May be <code>null</code>.
  581. */
  582. public void setDescription(String description) {
  583. this.description = description;
  584. }
  585. /**
  586. * Return the project description, if one has been set.
  587. *
  588. * @return the project description, or <code>null</code> if it hasn't
  589. * been set.
  590. */
  591. public String getDescription() {
  592. if (description == null) {
  593. description = Description.getDescription(this);
  594. }
  595. return description;
  596. }
  597. /**
  598. * Add a filter to the set of global filters.
  599. *
  600. * @param token The token to filter.
  601. * Must not be <code>null</code>.
  602. * @param value The replacement value.
  603. * Must not be <code>null</code>.
  604. * @deprecated Use getGlobalFilterSet().addFilter(token,value)
  605. *
  606. * @see #getGlobalFilterSet()
  607. * @see FilterSet#addFilter(String,String)
  608. */
  609. public void addFilter(String token, String value) {
  610. if (token == null) {
  611. return;
  612. }
  613. globalFilterSet.addFilter(new FilterSet.Filter(token, value));
  614. }
  615. /**
  616. * Return a hashtable of global filters, mapping tokens to values.
  617. *
  618. * @return a hashtable of global filters, mapping tokens to values
  619. * (String to String).
  620. *
  621. * @deprecated Use getGlobalFilterSet().getFilterHash()
  622. *
  623. * @see #getGlobalFilterSet()
  624. * @see FilterSet#getFilterHash()
  625. */
  626. public Hashtable getFilters() {
  627. // we need to build the hashtable dynamically
  628. return globalFilterSet.getFilterHash();
  629. }
  630. /**
  631. * Set the base directory for the project, checking that
  632. * the given filename exists and is a directory.
  633. *
  634. * @param baseD The project base directory.
  635. * Must not be <code>null</code>.
  636. *
  637. * @exception BuildException if the directory if invalid.
  638. */
  639. public void setBasedir(String baseD) throws BuildException {
  640. setBaseDir(new File(baseD));
  641. }
  642. /**
  643. * Set the base directory for the project, checking that
  644. * the given file exists and is a directory.
  645. *
  646. * @param baseDir The project base directory.
  647. * Must not be <code>null</code>.
  648. * @exception BuildException if the specified file doesn't exist or
  649. * isn't a directory.
  650. */
  651. public void setBaseDir(File baseDir) throws BuildException {
  652. baseDir = FILE_UTILS.normalize(baseDir.getAbsolutePath());
  653. if (!baseDir.exists()) {
  654. throw new BuildException("Basedir " + baseDir.getAbsolutePath()
  655. + " does not exist");
  656. }
  657. if (!baseDir.isDirectory()) {
  658. throw new BuildException("Basedir " + baseDir.getAbsolutePath()
  659. + " is not a directory");
  660. }
  661. this.baseDir = baseDir;
  662. setPropertyInternal("basedir", this.baseDir.getPath());
  663. String msg = "Project base dir set to: " + this.baseDir;
  664. log(msg, MSG_VERBOSE);
  665. }
  666. /**
  667. * Return the base directory of the project as a file object.
  668. *
  669. * @return the project base directory, or <code>null</code> if the
  670. * base directory has not been successfully set to a valid value.
  671. */
  672. public File getBaseDir() {
  673. if (baseDir == null) {
  674. try {
  675. setBasedir(".");
  676. } catch (BuildException ex) {
  677. ex.printStackTrace();
  678. }
  679. }
  680. return baseDir;
  681. }
  682. /**
  683. * Set &quot;keep-going&quot; mode. In this mode Ant will try to execute
  684. * as many targets as possible. All targets that do not depend
  685. * on failed target(s) will be executed. If the keepGoing settor/getter
  686. * methods are used in conjunction with the <code>ant.executor.class</code>
  687. * property, they will have no effect.
  688. * @param keepGoingMode &quot;keep-going&quot; mode
  689. * @since Ant 1.6
  690. */
  691. public void setKeepGoingMode(boolean keepGoingMode) {
  692. this.keepGoingMode = keepGoingMode;
  693. }
  694. /**
  695. * Return the keep-going mode. If the keepGoing settor/getter
  696. * methods are used in conjunction with the <code>ant.executor.class</code>
  697. * property, they will have no effect.
  698. * @return &quot;keep-going&quot; mode
  699. * @since Ant 1.6
  700. */
  701. public boolean isKeepGoingMode() {
  702. return this.keepGoingMode;
  703. }
  704. /**
  705. * Return the version of Java this class is running under.
  706. * @return the version of Java as a String, e.g. "1.1" .
  707. * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
  708. * @deprecated use org.apache.tools.ant.util.JavaEnvUtils instead
  709. */
  710. public static String getJavaVersion() {
  711. return JavaEnvUtils.getJavaVersion();
  712. }
  713. /**
  714. * Set the <code>ant.java.version</code> property and tests for
  715. * unsupported JVM versions. If the version is supported,
  716. * verbose log messages are generated to record the Java version
  717. * and operating system name.
  718. *
  719. * @exception BuildException if this Java version is not supported.
  720. *
  721. * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
  722. */
  723. public void setJavaVersionProperty() throws BuildException {
  724. String javaVersion = JavaEnvUtils.getJavaVersion();
  725. setPropertyInternal("ant.java.version", javaVersion);
  726. // sanity check
  727. if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0)) {
  728. throw new BuildException("Ant cannot work on Java 1.0");
  729. }
  730. log("Detected Java version: " + javaVersion + " in: "
  731. + System.getProperty("java.home"), MSG_VERBOSE);
  732. log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
  733. }
  734. /**
  735. * Add all system properties which aren't already defined as
  736. * user properties to the project properties.
  737. */
  738. public void setSystemProperties() {
  739. Properties systemP = System.getProperties();
  740. Enumeration e = systemP.propertyNames();
  741. while (e.hasMoreElements()) {
  742. String propertyName = (String) e.nextElement();
  743. String value = systemP.getProperty(propertyName);
  744. this.setPropertyInternal(propertyName, value);
  745. }
  746. }
  747. /**
  748. * Add a new task definition to the project.
  749. * Attempting to override an existing definition with an
  750. * equivalent one (i.e. with the same classname) results in
  751. * a verbose log message. Attempting to override an existing definition
  752. * with a different one results in a warning log message and
  753. * invalidates any tasks which have already been created with the
  754. * old definition.
  755. *
  756. * @param taskName The name of the task to add.
  757. * Must not be <code>null</code>.
  758. * @param taskClass The full name of the class implementing the task.
  759. * Must not be <code>null</code>.
  760. *
  761. * @exception BuildException if the class is unsuitable for being an Ant
  762. * task. An error level message is logged before
  763. * this exception is thrown.
  764. *
  765. * @see #checkTaskClass(Class)
  766. */
  767. public void addTaskDefinition(String taskName, Class taskClass)
  768. throws BuildException {
  769. ComponentHelper.getComponentHelper(this).addTaskDefinition(taskName,
  770. taskClass);
  771. }
  772. /**
  773. * Check whether or not a class is suitable for serving as Ant task.
  774. * Ant task implementation classes must be public, concrete, and have
  775. * a no-arg constructor.
  776. *
  777. * @param taskClass The class to be checked.
  778. * Must not be <code>null</code>.
  779. *
  780. * @exception BuildException if the class is unsuitable for being an Ant
  781. * task. An error level message is logged before
  782. * this exception is thrown.
  783. */
  784. public void checkTaskClass(final Class taskClass) throws BuildException {
  785. ComponentHelper.getComponentHelper(this).checkTaskClass(taskClass);
  786. if (!Modifier.isPublic(taskClass.getModifiers())) {
  787. final String message = taskClass + " is not public";
  788. log(message, Project.MSG_ERR);
  789. throw new BuildException(message);
  790. }
  791. if (Modifier.isAbstract(taskClass.getModifiers())) {
  792. final String message = taskClass + " is abstract";
  793. log(message, Project.MSG_ERR);
  794. throw new BuildException(message);
  795. }
  796. try {
  797. taskClass.getConstructor((Class[]) null);
  798. // don't have to check for public, since
  799. // getConstructor finds public constructors only.
  800. } catch (NoSuchMethodException e) {
  801. final String message = "No public no-arg constructor in "
  802. + taskClass;
  803. log(message, Project.MSG_ERR);
  804. throw new BuildException(message);
  805. } catch (LinkageError e) {
  806. String message = "Could not load " + taskClass + ": " + e;
  807. log(message, Project.MSG_ERR);
  808. throw new BuildException(message, e);
  809. }
  810. if (!Task.class.isAssignableFrom(taskClass)) {
  811. TaskAdapter.checkTaskClass(taskClass, this);
  812. }
  813. }
  814. /**
  815. * Return the current task definition hashtable. The returned hashtable is
  816. * &quot;live&quot; and so should not be modified.
  817. *
  818. * @return a map of from task name to implementing class
  819. * (String to Class).
  820. */
  821. public Hashtable getTaskDefinitions() {
  822. return ComponentHelper.getComponentHelper(this).getTaskDefinitions();
  823. }
  824. /**
  825. * Add a new datatype definition.
  826. * Attempting to override an existing definition with an
  827. * equivalent one (i.e. with the same classname) results in
  828. * a verbose log message. Attempting to override an existing definition
  829. * with a different one results in a warning log message, but the
  830. * definition is changed.
  831. *
  832. * @param typeName The name of the datatype.
  833. * Must not be <code>null</code>.
  834. * @param typeClass The full name of the class implementing the datatype.
  835. * Must not be <code>null</code>.
  836. */
  837. public void addDataTypeDefinition(String typeName, Class typeClass) {
  838. ComponentHelper.getComponentHelper(this).addDataTypeDefinition(typeName,
  839. typeClass);
  840. }
  841. /**
  842. * Return the current datatype definition hashtable. The returned
  843. * hashtable is &quot;live&quot; and so should not be modified.
  844. *
  845. * @return a map of from datatype name to implementing class
  846. * (String to Class).
  847. */
  848. public Hashtable getDataTypeDefinitions() {
  849. return ComponentHelper.getComponentHelper(this).getDataTypeDefinitions();
  850. }
  851. /**
  852. * Add a <em>new</em> target to the project.
  853. *
  854. * @param target The target to be added to the project.
  855. * Must not be <code>null</code>.
  856. *
  857. * @exception BuildException if the target already exists in the project
  858. *
  859. * @see Project#addOrReplaceTarget(Target)
  860. */
  861. public void addTarget(Target target) throws BuildException {
  862. addTarget(target.getName(), target);
  863. }
  864. /**
  865. * Add a <em>new</em> target to the project.
  866. *
  867. * @param targetName The name to use for the target.
  868. * Must not be <code>null</code>.
  869. * @param target The target to be added to the project.
  870. * Must not be <code>null</code>.
  871. *
  872. * @exception BuildException if the target already exists in the project.
  873. *
  874. * @see Project#addOrReplaceTarget(String, Target)
  875. */
  876. public void addTarget(String targetName, Target target)
  877. throws BuildException {
  878. if (targets.get(targetName) != null) {
  879. throw new BuildException("Duplicate target: `" + targetName + "'");
  880. }
  881. addOrReplaceTarget(targetName, target);
  882. }
  883. /**
  884. * Add a target to the project, or replaces one with the same
  885. * name.
  886. *
  887. * @param target The target to be added or replaced in the project.
  888. * Must not be <code>null</code>.
  889. */
  890. public void addOrReplaceTarget(Target target) {
  891. addOrReplaceTarget(target.getName(), target);
  892. }
  893. /**
  894. * Add a target to the project, or replaces one with the same
  895. * name.
  896. *
  897. * @param targetName The name to use for the target.
  898. * Must not be <code>null</code>.
  899. * @param target The target to be added or replaced in the project.
  900. * Must not be <code>null</code>.
  901. */
  902. public void addOrReplaceTarget(String targetName, Target target) {
  903. String msg = " +Target: " + targetName;
  904. log(msg, MSG_DEBUG);
  905. target.setProject(this);
  906. targets.put(targetName, target);
  907. }
  908. /**
  909. * Return the hashtable of targets. The returned hashtable
  910. * is &quot;live&quot; and so should not be modified.
  911. * @return a map from name to target (String to Target).
  912. */
  913. public Hashtable getTargets() {
  914. return targets;
  915. }
  916. /**
  917. * Create a new instance of a task, adding it to a list of
  918. * created tasks for later invalidation. This causes all tasks
  919. * to be remembered until the containing project is removed
  920. * @param taskType The name of the task to create an instance of.
  921. * Must not be <code>null</code>.
  922. *
  923. * @return an instance of the specified task, or <code>null</code> if
  924. * the task name is not recognised.
  925. *
  926. * @exception BuildException if the task name is recognised but task
  927. * creation fails.
  928. */
  929. public Task createTask(String taskType) throws BuildException {
  930. return ComponentHelper.getComponentHelper(this).createTask(taskType);
  931. }
  932. /**
  933. * Create a new instance of a data type.
  934. *
  935. * @param typeName The name of the data type to create an instance of.
  936. * Must not be <code>null</code>.
  937. *
  938. * @return an instance of the specified data type, or <code>null</code> if
  939. * the data type name is not recognised.
  940. *
  941. * @exception BuildException if the data type name is recognised but
  942. * instance creation fails.
  943. */
  944. public Object createDataType(String typeName) throws BuildException {
  945. return ComponentHelper.getComponentHelper(this).createDataType(typeName);
  946. }
  947. /**
  948. * Set the Executor instance for this Project.
  949. * @param e the Executor to use.
  950. */
  951. public void setExecutor(Executor e) {
  952. addReference("ant.executor", e);
  953. }
  954. /**
  955. * Get this Project's Executor (setting it if necessary).
  956. * @return an Executor instance.
  957. */
  958. public Executor getExecutor() {
  959. Object o = getReference("ant.executor");
  960. if (o == null) {
  961. String classname = getProperty("ant.executor.class");
  962. if (classname == null) {
  963. classname = DefaultExecutor.class.getName();
  964. }
  965. log("Attempting to create object of type " + classname, MSG_DEBUG);
  966. try {
  967. o = Class.forName(classname, true, coreLoader).newInstance();
  968. } catch (ClassNotFoundException seaEnEfEx) {
  969. //try the current classloader
  970. try {
  971. o = Class.forName(classname).newInstance();
  972. } catch (Exception ex) {
  973. log(ex.toString(), MSG_ERR);
  974. }
  975. } catch (Exception ex) {
  976. log(ex.toString(), MSG_ERR);
  977. }
  978. if (o == null) {
  979. throw new BuildException(
  980. "Unable to obtain a Target Executor instance.");
  981. }
  982. setExecutor((Executor) o);
  983. }
  984. return (Executor) o;
  985. }
  986. /**
  987. * Execute the specified sequence of targets, and the targets
  988. * they depend on.
  989. *
  990. * @param names A vector of target name strings to execute.
  991. * Must not be <code>null</code>.
  992. *
  993. * @exception BuildException if the build failed.
  994. */
  995. public void executeTargets(Vector names) throws BuildException {
  996. getExecutor().executeTargets(this,
  997. (String[]) (names.toArray(new String[names.size()])));
  998. }
  999. /**
  1000. * Demultiplex output so that each task receives the appropriate
  1001. * messages. If the current thread is not currently executing a task,
  1002. * the message is logged directly.
  1003. *
  1004. * @param output Message to handle. Should not be <code>null</code>.
  1005. * @param isWarning Whether the text represents an warning (<code>true</code>)
  1006. * or information (<code>false</code>).
  1007. */
  1008. public void demuxOutput(String output, boolean isWarning) {
  1009. Task task = getThreadTask(Thread.currentThread());
  1010. if (task == null) {
  1011. log(output, isWarning ? MSG_WARN : MSG_INFO);
  1012. } else {
  1013. if (isWarning) {
  1014. task.handleErrorOutput(output);
  1015. } else {
  1016. task.handleOutput(output);
  1017. }
  1018. }
  1019. }
  1020. /**
  1021. * Read data from the default input stream. If no default has been
  1022. * specified, System.in is used.
  1023. *
  1024. * @param buffer the buffer into which data is to be read.
  1025. * @param offset the offset into the buffer at which data is stored.
  1026. * @param length the amount of data to read.
  1027. *
  1028. * @return the number of bytes read.
  1029. *
  1030. * @exception IOException if the data cannot be read.
  1031. * @since Ant 1.6
  1032. */
  1033. public int defaultInput(byte[] buffer, int offset, int length)
  1034. throws IOException {
  1035. if (defaultInputStream != null) {
  1036. System.out.flush();
  1037. return defaultInputStream.read(buffer, offset, length);
  1038. } else {
  1039. throw new EOFException("No input provided for project");
  1040. }
  1041. }
  1042. /**
  1043. * Demux an input request to the correct task.
  1044. *
  1045. * @param buffer the buffer into which data is to be read.
  1046. * @param offset the offset into the buffer at which data is stored.
  1047. * @param length the amount of data to read.
  1048. *
  1049. * @return the number of bytes read.
  1050. *
  1051. * @exception IOException if the data cannot be read.
  1052. * @since Ant 1.6
  1053. */
  1054. public int demuxInput(byte[] buffer, int offset, int length)
  1055. throws IOException {
  1056. Task task = getThreadTask(Thread.currentThread());
  1057. if (task == null) {
  1058. return defaultInput(buffer, offset, length);
  1059. } else {
  1060. return task.handleInput(buffer, offset, length);
  1061. }
  1062. }
  1063. /**
  1064. * Demultiplex flush operations so that each task receives the appropriate
  1065. * messages. If the current thread is not currently executing a task,
  1066. * the message is logged directly.
  1067. *
  1068. * @since Ant 1.5.2
  1069. *
  1070. * @param output Message to handle. Should not be <code>null</code>.
  1071. * @param isError Whether the text represents an error (<code>true</code>)
  1072. * or information (<code>false</code>).
  1073. */
  1074. public void demuxFlush(String output, boolean isError) {
  1075. Task task = getThreadTask(Thread.currentThread());
  1076. if (task == null) {
  1077. fireMessageLogged(this, output, isError ? MSG_ERR : MSG_INFO);
  1078. } else {
  1079. if (isError) {
  1080. task.handleErrorFlush(output);
  1081. } else {
  1082. task.handleFlush(output);
  1083. }
  1084. }
  1085. }
  1086. /**
  1087. * Execute the specified target and any targets it depends on.
  1088. *
  1089. * @param targetName The name of the target to execute.
  1090. * Must not be <code>null</code>.
  1091. *
  1092. * @exception BuildException if the build failed.
  1093. */
  1094. public void executeTarget(String targetName) throws BuildException {
  1095. // sanity check ourselves, if we've been asked to build nothing
  1096. // then we should complain
  1097. if (targetName == null) {
  1098. String msg = "No target specified";
  1099. throw new BuildException(msg);
  1100. }
  1101. // Sort and run the dependency tree.
  1102. // Sorting checks if all the targets (and dependencies)
  1103. // exist, and if there is any cycle in the dependency
  1104. // graph.
  1105. executeSortedTargets(topoSort(targetName, targets, false));
  1106. }
  1107. /**
  1108. * Execute a <code>Vector</code> of sorted targets.
  1109. * @param sortedTargets the aforementioned <code>Vector</code>.
  1110. * @throws BuildException on error.
  1111. */
  1112. public void executeSortedTargets(Vector sortedTargets)
  1113. throws BuildException {
  1114. Set succeededTargets = new HashSet();
  1115. BuildException buildException = null; // first build exception
  1116. for (Enumeration iter = sortedTargets.elements();
  1117. iter.hasMoreElements();) {
  1118. Target curtarget = (Target) iter.nextElement();
  1119. boolean canExecute = true;
  1120. for (Enumeration depIter = curtarget.getDependencies();
  1121. depIter.hasMoreElements();) {
  1122. String dependencyName = ((String) depIter.nextElement());
  1123. if (!succeededTargets.contains(dependencyName)) {
  1124. canExecute = false;
  1125. log(curtarget,
  1126. "Cannot execute '" + curtarget.getName() + "' - '"
  1127. + dependencyName + "' failed or was not executed.",
  1128. MSG_ERR);
  1129. break;
  1130. }
  1131. }
  1132. if (canExecute) {
  1133. Throwable thrownException = null;
  1134. try {
  1135. curtarget.performTasks();
  1136. succeededTargets.add(curtarget.getName());
  1137. } catch (RuntimeException ex) {
  1138. if (!(keepGoingMode)) {
  1139. throw ex; // throw further
  1140. }
  1141. thrownException = ex;
  1142. } catch (Throwable ex) {
  1143. if (!(keepGoingMode)) {
  1144. throw new BuildException(ex);
  1145. }
  1146. thrownException = ex;
  1147. }
  1148. if (thrownException != null) {
  1149. if (thrownException instanceof BuildException) {
  1150. log(curtarget,
  1151. "Target '" + curtarget.getName()
  1152. + "' failed with message '"
  1153. + thrownException.getMessage() + "'.", MSG_ERR);
  1154. // only the first build exception is reported
  1155. if (buildException == null) {
  1156. buildException = (BuildException) thrownException;
  1157. }
  1158. } else {
  1159. log(curtarget,
  1160. "Target '" + curtarget.getName()
  1161. + "' failed with message '"
  1162. + thrownException.getMessage() + "'.", MSG_ERR);
  1163. thrownException.printStackTrace(System.err);
  1164. if (buildException == null) {
  1165. buildException =
  1166. new BuildException(thrownException);
  1167. }
  1168. }
  1169. }
  1170. }
  1171. }
  1172. if (buildException != null) {
  1173. throw buildException;
  1174. }
  1175. }
  1176. /**
  1177. * Return the canonical form of a filename.
  1178. * <p>
  1179. * If the specified file name is relative it is resolved
  1180. * with respect to the given root directory.
  1181. *
  1182. * @param fileName The name of the file to resolve.
  1183. * Must not be <code>null</code>.
  1184. *
  1185. * @param rootDir The directory respective to which relative file names
  1186. * are resolved. May be <code>null</code>, in which case
  1187. * the current directory is used.
  1188. *
  1189. * @return the resolved File.
  1190. *
  1191. * @deprecated
  1192. */
  1193. public File resolveFile(String fileName, File rootDir) {
  1194. return FILE_UTILS.resolveFile(rootDir, fileName);
  1195. }
  1196. /**
  1197. * Return the canonical form of a filename.
  1198. * <p>
  1199. * If the specified file name is relative it is resolved
  1200. * with respect to the project's base directory.
  1201. *
  1202. * @param fileName The name of the file to resolve.
  1203. * Must not be <code>null</code>.
  1204. *
  1205. * @return the resolved File.
  1206. *
  1207. */
  1208. public File resolveFile(String fileName) {
  1209. return FILE_UTILS.resolveFile(baseDir, fileName);
  1210. }
  1211. /**
  1212. * Translate a path into its native (platform specific) format.
  1213. * <p>
  1214. * This method uses PathTokenizer to separate the input path
  1215. * into its components. This handles DOS style paths in a relatively
  1216. * sensible way. The file separators are then converted to their platform
  1217. * specific versions.
  1218. *
  1219. * @param toProcess The path to be translated.
  1220. * May be <code>null</code>.
  1221. *
  1222. * @return the native version of the specified path or
  1223. * an empty string if the path is <code>null</code> or empty.
  1224. *
  1225. * @see PathTokenizer
  1226. */
  1227. public static String translatePath(String toProcess) {
  1228. if (toProcess == null || toProcess.length() == 0) {
  1229. return "";
  1230. }
  1231. StringBuffer path = new StringBuffer(toProcess.length() + 50);
  1232. PathTokenizer tokenizer = new PathTokenizer(toProcess);
  1233. while (tokenizer.hasMoreTokens()) {
  1234. String pathComponent = tokenizer.nextToken();
  1235. pathComponent = pathComponent.replace('/', File.separatorChar);
  1236. pathComponent = pathComponent.replace('\\', File.separatorChar);
  1237. if (path.length() != 0) {
  1238. path.append(File.pathSeparatorChar);
  1239. }
  1240. path.append(pathComponent);
  1241. }
  1242. return path.toString();
  1243. }
  1244. /**
  1245. * Convenience method to copy a file from a source to a destination.
  1246. * No filtering is performed.
  1247. *
  1248. * @param sourceFile Name of file to copy from.
  1249. * Must not be <code>null</code>.
  1250. * @param destFile Name of file to copy to.
  1251. * Must not be <code>null</code>.
  1252. *
  1253. * @exception IOException if the copying fails.
  1254. *
  1255. * @deprecated
  1256. */
  1257. public void copyFile(String sourceFile, String destFile)
  1258. throws IOException {
  1259. FILE_UTILS.copyFile(sourceFile, destFile);
  1260. }
  1261. /**
  1262. * Convenience method to copy a file from a source to a destination
  1263. * specifying if token filtering should be used.
  1264. *
  1265. * @param sourceFile Name of file to copy from.
  1266. * Must not be <code>null</code>.
  1267. * @param destFile Name of file to copy to.
  1268. * Must not be <code>null</code>.
  1269. * @param filtering Whether or not token filtering should be used during
  1270. * the copy.
  1271. *
  1272. * @exception IOException if the copying fails.
  1273. *
  1274. * @deprecated
  1275. */
  1276. public void copyFile(String sourceFile, String destFile, boolean filtering)
  1277. throws IOException {
  1278. FILE_UTILS.copyFile(sourceFile, destFile,
  1279. filtering ? globalFilters : null);
  1280. }
  1281. /**
  1282. * Convenience method to copy a file from a source to a
  1283. * destination specifying if token filtering should be used and if
  1284. * source files may overwrite newer destination files.
  1285. *
  1286. * @param sourceFile Name of file to copy from.
  1287. * Must not be <code>null</code>.
  1288. * @param destFile Name of 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. * @param overwrite Whether or not the destination file should be
  1293. * overwritten if it already exists.
  1294. *
  1295. * @exception IOException if the copying fails.
  1296. *
  1297. * @deprecated
  1298. */
  1299. public void copyFile(String sourceFile, String destFile, boolean filtering,
  1300. boolean overwrite) throws IOException {
  1301. FILE_UTILS.copyFile(sourceFile, destFile,
  1302. filtering ? globalFilters : null, overwrite);
  1303. }
  1304. /**
  1305. * Convenience method to copy a file from a source to a
  1306. * destination specifying if token filtering should be used, if
  1307. * source files may overwrite newer destination files, and if the
  1308. * last modified time of the resulting file should be set to
  1309. * that of the source file.
  1310. *
  1311. * @param sourceFile Name of file to copy from.
  1312. * Must not be <code>null</code>.
  1313. * @param destFile Name of file to copy to.
  1314. * Must not be <code>null</code>.
  1315. * @param filtering Whether or not token filtering should be used during
  1316. * the copy.
  1317. * @param overwrite Whether or not the destination file should be
  1318. * overwritten if it already exists.
  1319. * @param preserveLastModified Whether or not the last modified time of
  1320. * the resulting file should be set to that
  1321. * of the source file.
  1322. *
  1323. * @exception IOException if the copying fails.
  1324. *
  1325. * @deprecated
  1326. */
  1327. public void copyFile(String sourceFile, String destFile, boolean filtering,
  1328. boolean overwrite, boolean preserveLastModified)
  1329. throws IOException {
  1330. FILE_UTILS.copyFile(sourceFile, destFile,
  1331. filtering ? globalFilters : null, overwrite, preserveLastModified);
  1332. }
  1333. /**
  1334. * Convenience method to copy a file from a source to a destination.
  1335. * No filtering is performed.
  1336. *
  1337. * @param sourceFile File to copy from.
  1338. * Must not be <code>null</code>.
  1339. * @param destFile File to copy to.
  1340. * Must not be <code>null</code>.
  1341. *
  1342. * @exception IOException if the copying fails.
  1343. *
  1344. * @deprecated
  1345. */
  1346. public void copyFile(File sourceFile, File destFile) throws IOException {
  1347. FILE_UTILS.copyFile(sourceFile, destFile);
  1348. }
  1349. /**
  1350. * Convenience method to copy a file from a source to a destination
  1351. * specifying if token filtering should be used.
  1352. *
  1353. * @param sourceFile File to copy from.
  1354. * Must not be <code>null</code>.
  1355. * @param destFile File to copy to.
  1356. * Must not be <code>null</code>.
  1357. * @param filtering Whether or not token filtering should be used during
  1358. * the copy.
  1359. *
  1360. * @exception IOException if the copying fails.
  1361. *
  1362. * @deprecated
  1363. */
  1364. public void copyFile(File sourceFile, File destFile, boolean filtering)
  1365. throws IOException {
  1366. FILE_UTILS.copyFile(sourceFile, destFile,
  1367. filtering ? globalFilters : null);
  1368. }
  1369. /**
  1370. * Convenience method to copy a file from a source to a
  1371. * destination specifying if token filtering should be used and if
  1372. * source files may overwrite newer destination files.
  1373. *
  1374. * @param sourceFile File to copy from.
  1375. * Must not be <code>null</code>.
  1376. * @param destFile File to copy to.
  1377. * Must not be <code>null</code>.
  1378. * @param filtering Whether or not token filtering should be used during
  1379. * the copy.
  1380. * @param overwrite Whether or not the destination file should be
  1381. * overwritten if it already exists.
  1382. *
  1383. * @exception IOException if the file cannot be copied.
  1384. *
  1385. * @deprecated
  1386. */
  1387. public void copyFile(File sourceFile, File destFile, boolean filtering,
  1388. boolean overwrite) throws IOException {
  1389. FILE_UTILS.copyFile(sourceFile, destFile,
  1390. filtering ? globalFilters : null, overwrite);
  1391. }
  1392. /**
  1393. * Convenience method to copy a file from a source to a
  1394. * destination specifying if token filtering should be used, if
  1395. * source files may overwrite newer destination files, and if the
  1396. * last modified time of the resulting file should be set to
  1397. * that of the source file.
  1398. *
  1399. * @param sourceFile File to copy from.
  1400. * Must not be <code>null</code>.
  1401. * @param destFile File to copy to.
  1402. * Must not be <code>null</code>.
  1403. * @param filtering Whether or not token filtering should be used during
  1404. * the copy.
  1405. * @param overwrite Whether or not the destination file should be
  1406. * overwritten if it already exists.
  1407. * @param preserveLastModified Whether or not the last modified time of
  1408. * the resulting file should be set to that
  1409. * of the source file.
  1410. *
  1411. * @exception IOException if the file cannot be copied.
  1412. *
  1413. * @deprecated
  1414. */
  1415. public void copyFile(File sourceFile, File destFile, boolean filtering,
  1416. boolean overwrite, boolean preserveLastModified)
  1417. throws IOException {
  1418. FILE_UTILS.copyFile(sourceFile, destFile,
  1419. filtering ? globalFilters : null, overwrite, preserveLastModified);
  1420. }
  1421. /**
  1422. * Call File.setLastModified(long time) on Java above 1.1, and logs
  1423. * a warning on Java 1.1.
  1424. *
  1425. * @param file The file to set the last modified time on.
  1426. * Must not be <code>null</code>.
  1427. *
  1428. * @param time the required modification time.
  1429. *
  1430. * @deprecated
  1431. *
  1432. * @exception BuildException if the last modified time cannot be set
  1433. * despite running on a platform with a version
  1434. * above 1.1.
  1435. */
  1436. public void setFileLastModified(File file, long time)
  1437. throws BuildException {
  1438. FILE_UTILS.setFileLastModified(file, time);
  1439. log("Setting modification time for " + file, MSG_VERBOSE);
  1440. }
  1441. /**
  1442. * Return the boolean equivalent of a string, which is considered
  1443. * <code>true</code> if either <code>"on"</code>, <code>"true"</code>,
  1444. * or <code>"yes"</code> is found, ignoring case.
  1445. *
  1446. * @param s The string to convert to a boolean value.
  1447. *
  1448. * @return <code>true</code> if the given string is <code>"on"</code>,
  1449. * <code>"true"</code> or <code>"yes"</code>, or
  1450. * <code>false</code> otherwise.
  1451. */
  1452. public static boolean toBoolean(String s) {
  1453. return ("on".equalsIgnoreCase(s)
  1454. || "true".equalsIgnoreCase(s)
  1455. || "yes".equalsIgnoreCase(s));
  1456. }
  1457. /**
  1458. * Topologically sort a set of targets. Equivalent to calling
  1459. * <code>topoSort(new String[] {root}, targets, true)</code>.
  1460. *
  1461. * @param root The name of the root target. The sort is created in such
  1462. * a way that the sequence of Targets up to the root
  1463. * target is the minimum possible such sequence.
  1464. * Must not be <code>null</code>.
  1465. * @param targetTable A Hashtable mapping names to Targets.
  1466. * Must not be <code>null</code>.
  1467. * @return a Vector of ALL Target objects in sorted order.
  1468. * @exception BuildException if there is a cyclic dependency among the
  1469. * targets, or if a named target does not exist.
  1470. */
  1471. public final Vector topoSort(String root, Hashtable targetTable)
  1472. throws BuildException {
  1473. return topoSort(new String[] {root}, targetTable, true);
  1474. }
  1475. /**
  1476. * Topologically sort a set of targets. Equivalent to calling
  1477. * <code>topoSort(new String[] {root}, targets, returnAll)</code>.
  1478. *
  1479. * @param root The name of the root target. The sort is created in such
  1480. * a way that the sequence of Targets up to the root
  1481. * target is the minimum possible such sequence.
  1482. * Must not be <code>null</code>.
  1483. * @param targetTable A Hashtable mapping names to Targets.
  1484. * Must not be <code>null</code>.
  1485. * @param returnAll <code>boolean</code> indicating whether to return all
  1486. * targets, or the execution sequence only.
  1487. * @return a Vector of Target objects in sorted order.
  1488. * @exception BuildException if there is a cyclic dependency among the
  1489. * targets, or if a named target does not exist.
  1490. * @since Ant 1.6.3
  1491. */
  1492. public final Vector topoSort(String root, Hashtable targetTable,
  1493. boolean returnAll) throws BuildException {
  1494. return topoSort(new String[] {root}, targetTable, returnAll);
  1495. }
  1496. /**
  1497. * Topologically sort a set of targets.
  1498. *
  1499. * @param root <code>String[]</code> containing the names of the root targets.
  1500. * The sort is created in such a way that the ordered sequence of
  1501. * Targets is the minimum possible such sequence to the specified
  1502. * root targets.
  1503. * Must not be <code>null</code>.
  1504. * @param targetTable A map of names to targets (String to Target).
  1505. * Must not be <code>null</code>.
  1506. * @param returnAll <code>boolean</code> indicating whether to return all
  1507. * targets, or the execution sequence only.
  1508. * @return a Vector of Target objects in sorted order.
  1509. * @exception BuildException if there is a cyclic dependency among the
  1510. * targets, or if a named target does not exist.
  1511. * @since Ant 1.6.3
  1512. */
  1513. public final Vector topoSort(String[] root, Hashtable targetTable,
  1514. boolean returnAll) throws BuildException {
  1515. Vector ret = new Vector();
  1516. Hashtable state = new Hashtable();
  1517. Stack visiting = new Stack();
  1518. // We first run a DFS based sort using each root as a starting node.
  1519. // This creates the minimum sequence of Targets to the root node(s).
  1520. // We then do a sort on any remaining unVISITED targets.
  1521. // This is unnecessary for doing our build, but it catches
  1522. // circular dependencies or missing Targets on the entire
  1523. // dependency tree, not just on the Targets that depend on the
  1524. // build Target.
  1525. for (int i = 0; i < root.length; i++) {
  1526. String st = (String) (state.get(root[i]));
  1527. if (st == null) {
  1528. tsort(root[i], targetTable, state, visiting, ret);
  1529. } else if (st == VISITING) {
  1530. throw new RuntimeException("Unexpected node in visiting state: "
  1531. + root[i]);
  1532. }
  1533. }
  1534. StringBuffer buf = new StringBuffer("Build sequence for target(s)");
  1535. for (int j = 0; j < root.length; j++) {
  1536. buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\'');
  1537. }
  1538. buf.append(" is " + ret);
  1539. log(buf.toString(), MSG_VERBOSE);
  1540. Vector complete = (returnAll) ? ret : new Vector(ret);
  1541. for (Enumeration en = targetTable.keys(); en.hasMoreElements();) {
  1542. String curTarget = (String) en.nextElement();
  1543. String st = (String) state.get(curTarget);
  1544. if (st == null) {
  1545. tsort(curTarget, targetTable, state, visiting, complete);
  1546. } else if (st == VISITING) {
  1547. throw new RuntimeException("Unexpected node in visiting state: "
  1548. + curTarget);
  1549. }
  1550. }
  1551. log("Complete build sequence is " + complete, MSG_VERBOSE);
  1552. return ret;
  1553. }
  1554. /**
  1555. * Perform a single step in a recursive depth-first-search traversal of
  1556. * the target dependency tree.
  1557. * <p>
  1558. * The current target is first set to the &quot;visiting&quot; state, and
  1559. * pushed onto the &quot;visiting&quot; stack.
  1560. * <p>
  1561. * An exception is then thrown if any child of the current node is in the
  1562. * visiting state, as that implies a circular dependency. The exception
  1563. * contains details of the cycle, using elements of the &quot;visiting&quot;
  1564. * stack.
  1565. * <p>
  1566. * If any child has not already been &quot;visited&quot;, this method is
  1567. * called recursively on it.
  1568. * <p>
  1569. * The current target is then added to the ordered list of targets. Note
  1570. * that this is performed after the children have been visited in order
  1571. * to get the correct order. The current target is set to the
  1572. * &quot;visited&quot; state.
  1573. * <p>
  1574. * By the time this method returns, the ordered list contains the sequence
  1575. * of targets up to and including the current target.
  1576. *
  1577. * @param root The current target to inspect.
  1578. * Must not be <code>null</code>.
  1579. * @param targetTable A mapping from names to targets (String to Target).
  1580. * Must not be <code>null</code>.
  1581. * @param state A mapping from target names to states (String to String).
  1582. * The states in question are &quot;VISITING&quot; and
  1583. * &quot;VISITED&quot;. Must not be <code>null</code>.
  1584. * @param visiting A stack of targets which are currently being visited.
  1585. * Must not be <code>null</code>.
  1586. * @param ret The list to add target names to. This will end up
  1587. * containing the complete list of dependencies in
  1588. * dependency order.
  1589. * Must not be <code>null</code>.
  1590. *
  1591. * @exception BuildException if a non-existent target is specified or if
  1592. * a circular dependency is detected.
  1593. */
  1594. private void tsort(String root, Hashtable targetTable,
  1595. Hashtable state, Stack visiting,
  1596. Vector ret)
  1597. throws BuildException {
  1598. state.put(root, VISITING);
  1599. visiting.push(root);
  1600. Target target = (Target) targetTable.get(root);
  1601. // Make sure we exist
  1602. if (target == null) {
  1603. StringBuffer sb = new StringBuffer("Target `");
  1604. sb.append(root);
  1605. sb.append("' does not exist in this project. ");
  1606. visiting.pop();
  1607. if (!visiting.empty()) {
  1608. String parent = (String) visiting.peek();
  1609. sb.append("It is used from target `");
  1610. sb.append(parent);
  1611. sb.append("'.");
  1612. }
  1613. throw new BuildException(new String(sb));
  1614. }
  1615. for (Enumeration en = target.getDependencies(); en.hasMoreElements();) {
  1616. String cur = (String) en.nextElement();
  1617. String m = (String) state.get(cur);
  1618. if (m == null) {
  1619. // Not been visited
  1620. tsort(cur, targetTable, state, visiting, ret);
  1621. } else if (m == VISITING) {
  1622. // Currently visiting this node, so have a cycle
  1623. throw makeCircularException(cur, visiting);
  1624. }
  1625. }
  1626. String p = (String) visiting.pop();
  1627. if (root != p) {
  1628. throw new RuntimeException("Unexpected internal error: expected to "
  1629. + "pop " + root + " but got " + p);
  1630. }
  1631. state.put(root, VISITED);
  1632. ret.addElement(target);
  1633. }
  1634. /**
  1635. * Build an appropriate exception detailing a specified circular
  1636. * dependency.
  1637. *
  1638. * @param end The dependency to stop at. Must not be <code>null</code>.
  1639. * @param stk A stack of dependencies. Must not be <code>null</code>.
  1640. *
  1641. * @return a BuildException detailing the specified circular dependency.
  1642. */
  1643. private static BuildException makeCircularException(String end, Stack stk) {
  1644. StringBuffer sb = new StringBuffer("Circular dependency: ");
  1645. sb.append(end);
  1646. String c;
  1647. do {
  1648. c = (String) stk.pop();
  1649. sb.append(" <- ");
  1650. sb.append(c);
  1651. } while (!c.equals(end));
  1652. return new BuildException(new String(sb));
  1653. }
  1654. /**
  1655. * Add a reference to the project.
  1656. *
  1657. * @param referenceName The name of the reference. Must not be <code>null</code>.
  1658. * @param value The value of the reference. Must not be <code>null</code>.
  1659. */
  1660. public void addReference(String referenceName, Object value) {
  1661. synchronized (references) {
  1662. Object old = ((AntRefTable) references).getReal(referenceName);
  1663. if (old == value) {
  1664. // no warning, this is not changing anything
  1665. return;
  1666. }
  1667. if (old != null && !(old instanceof UnknownElement)) {
  1668. log("Overriding previous definition of reference to " + referenceName,
  1669. MSG_WARN);
  1670. }
  1671. log("Adding reference: " + referenceName, MSG_DEBUG);
  1672. references.put(referenceName, value);
  1673. }
  1674. }
  1675. /**
  1676. * Return a map of the references in the project (String to Object).
  1677. * The returned hashtable is &quot;live&quot; and so must not be modified.
  1678. *
  1679. * @return a map of the references in the project (String to Object).
  1680. */
  1681. public Hashtable getReferences() {
  1682. return references;
  1683. }
  1684. /**
  1685. * Look up a reference by its key (ID).
  1686. *
  1687. * @param key The key for the desired reference.
  1688. * Must not be <code>null</code>.
  1689. *
  1690. * @return the reference with the specified ID, or <code>null</code> if
  1691. * there is no such reference in the project.
  1692. */
  1693. public Object getReference(String key) {
  1694. return references.get(key);
  1695. }
  1696. /**
  1697. * Return a description of the type of the given element, with
  1698. * special handling for instances of tasks and data types.
  1699. * <p>
  1700. * This is useful for logging purposes.
  1701. *
  1702. * @param element The element to describe.
  1703. * Must not be <code>null</code>.
  1704. *
  1705. * @return a description of the element type.
  1706. *
  1707. * @since 1.95, Ant 1.5
  1708. */
  1709. public String getElementName(Object element) {
  1710. return ComponentHelper.getComponentHelper(this).getElementName(element);
  1711. }
  1712. /**
  1713. * Send a &quot;build started&quot; event
  1714. * to the build listeners for this project.
  1715. */
  1716. public void fireBuildStarted() {
  1717. BuildEvent event = new BuildEvent(this);
  1718. Iterator iter = listeners.iterator();
  1719. while (iter.hasNext()) {
  1720. BuildListener listener = (BuildListener) iter.next();
  1721. listener.buildStarted(event);
  1722. }
  1723. }
  1724. /**
  1725. * Send a &quot;build finished&quot; event to the build listeners
  1726. * for this project.
  1727. * @param exception an exception indicating a reason for a build
  1728. * failure. May be <code>null</code>, indicating
  1729. * a successful build.
  1730. */
  1731. public void fireBuildFinished(Throwable exception) {
  1732. BuildEvent event = new BuildEvent(this);
  1733. event.setException(exception);
  1734. Iterator iter = listeners.iterator();
  1735. while (iter.hasNext()) {
  1736. BuildListener listener = (BuildListener) iter.next();
  1737. listener.buildFinished(event);
  1738. }
  1739. }
  1740. /**
  1741. * Send a &quot;subbuild started&quot; event to the build listeners for
  1742. * this project.
  1743. *
  1744. * @since Ant 1.6.2
  1745. */
  1746. public void fireSubBuildStarted() {
  1747. BuildEvent event = new BuildEvent(this);
  1748. Iterator iter = listeners.iterator();
  1749. while (iter.hasNext()) {
  1750. Object listener = iter.next();
  1751. if (listener instanceof SubBuildListener) {
  1752. ((SubBuildListener) listener).subBuildStarted(event);
  1753. }
  1754. }
  1755. }
  1756. /**
  1757. * Send a &quot;subbuild finished&quot; event to the build listeners for
  1758. * this project.
  1759. * @param exception an exception indicating a reason for a build
  1760. * failure. May be <code>null</code>, indicating
  1761. * a successful build.
  1762. *
  1763. * @since Ant 1.6.2
  1764. */
  1765. public void fireSubBuildFinished(Throwable exception) {
  1766. BuildEvent event = new BuildEvent(this);
  1767. event.setException(exception);
  1768. Iterator iter = listeners.iterator();
  1769. while (iter.hasNext()) {
  1770. Object listener = iter.next();
  1771. if (listener instanceof SubBuildListener) {
  1772. ((SubBuildListener) listener).subBuildFinished(event);
  1773. }
  1774. }
  1775. }
  1776. /**
  1777. * Send a &quot;target started&quot; event to the build listeners
  1778. * for this project.
  1779. *
  1780. * @param target The target which is starting to build.
  1781. * Must not be <code>null</code>.
  1782. */
  1783. protected void fireTargetStarted(Target target) {
  1784. BuildEvent event = new BuildEvent(target);
  1785. Iterator iter = listeners.iterator();
  1786. while (iter.hasNext()) {
  1787. BuildListener listener = (BuildListener) iter.next();
  1788. listener.targetStarted(event);
  1789. }
  1790. }
  1791. /**
  1792. * Send a &quot;target finished&quot; event to the build listeners
  1793. * for this project.
  1794. *
  1795. * @param target The target which has finished building.
  1796. * Must not be <code>null</code>.
  1797. * @param exception an exception indicating a reason for a build
  1798. * failure. May be <code>null</code>, indicating
  1799. * a successful build.
  1800. */
  1801. protected void fireTargetFinished(Target target, Throwable exception) {
  1802. BuildEvent event = new BuildEvent(target);
  1803. event.setException(exception);
  1804. Iterator iter = listeners.iterator();
  1805. while (iter.hasNext()) {
  1806. BuildListener listener = (BuildListener) iter.next();
  1807. listener.targetFinished(event);
  1808. }
  1809. }
  1810. /**
  1811. * Send a &quot;task started&quot; event to the build listeners
  1812. * for this project.
  1813. *
  1814. * @param task The target which is starting to execute.
  1815. * Must not be <code>null</code>.
  1816. */
  1817. protected void fireTaskStarted(Task task) {
  1818. // register this as the current task on the current thread.
  1819. registerThreadTask(Thread.currentThread(), task);
  1820. BuildEvent event = new BuildEvent(task);
  1821. Iterator iter = listeners.iterator();
  1822. while (iter.hasNext()) {
  1823. BuildListener listener = (BuildListener) iter.next();
  1824. listener.taskStarted(event);
  1825. }
  1826. }
  1827. /**
  1828. * Send a &quot;task finished&quot; event to the build listeners for this
  1829. * project.
  1830. *
  1831. * @param task The task which has finished executing.
  1832. * Must not be <code>null</code>.
  1833. * @param exception an exception indicating a reason for a build
  1834. * failure. May be <code>null</code>, indicating
  1835. * a successful build.
  1836. */
  1837. protected void fireTaskFinished(Task task, Throwable exception) {
  1838. registerThreadTask(Thread.currentThread(), null);
  1839. System.out.flush();
  1840. System.err.flush();
  1841. BuildEvent event = new BuildEvent(task);
  1842. event.setException(exception);
  1843. Iterator iter = listeners.iterator();
  1844. while (iter.hasNext()) {
  1845. BuildListener listener = (BuildListener) iter.next();
  1846. listener.taskFinished(event);
  1847. }
  1848. }
  1849. /**
  1850. * Send a &quot;message logged&quot; event to the build listeners
  1851. * for this project.
  1852. *
  1853. * @param event The event to send. This should be built up with the
  1854. * appropriate task/target/project by the caller, so that
  1855. * this method can set the message and priority, then send
  1856. * the event. Must not be <code>null</code>.
  1857. * @param message The message to send. Should not be <code>null</code>.
  1858. * @param priority The priority of the message.
  1859. */
  1860. private void fireMessageLoggedEvent(BuildEvent event, String message,
  1861. int priority) {
  1862. if (message.endsWith(StringUtils.LINE_SEP)) {
  1863. int endIndex = message.length() - StringUtils.LINE_SEP.length();
  1864. event.setMessage(message.substring(0, endIndex), priority);
  1865. } else {
  1866. event.setMessage(message, priority);
  1867. }
  1868. synchronized (this) {
  1869. if (loggingMessage) {
  1870. /*
  1871. * One of the Listeners has attempted to access
  1872. * System.err or System.out.
  1873. *
  1874. * We used to throw an exception in this case, but
  1875. * sometimes Listeners can't prevent it(like our own
  1876. * Log4jListener which invokes getLogger() which in
  1877. * turn wants to write to the console).
  1878. *
  1879. * @see http://marc.theaimsgroup.com/?t=110538624200006&r=1&w=2
  1880. *
  1881. * We now (Ant 1.7 and 1.6.3) simply swallow the message.
  1882. */
  1883. return;
  1884. }
  1885. try {
  1886. loggingMessage = true;
  1887. Iterator iter = listeners.iterator();
  1888. while (iter.hasNext()) {
  1889. BuildListener listener = (BuildListener) iter.next();
  1890. listener.messageLogged(event);
  1891. }
  1892. } finally {
  1893. loggingMessage = false;
  1894. }
  1895. }
  1896. }
  1897. /**
  1898. * Send a &quot;message logged&quot; project level event
  1899. * to the build listeners for this project.
  1900. *
  1901. * @param project The project generating the event.
  1902. * Should not be <code>null</code>.
  1903. * @param message The message to send. Should not be <code>null</code>.
  1904. * @param priority The priority of the message.
  1905. */
  1906. protected void fireMessageLogged(Project project, String message,
  1907. int priority) {
  1908. BuildEvent event = new BuildEvent(project);
  1909. fireMessageLoggedEvent(event, message, priority);
  1910. }
  1911. /**
  1912. * Send a &quot;message logged&quot; target level event
  1913. * to the build listeners for this project.
  1914. *
  1915. * @param target The target generating the event.
  1916. * Must not be <code>null</code>.
  1917. * @param message The message to send. Should not be <code>null</code>.
  1918. * @param priority The priority of the message.
  1919. */
  1920. protected void fireMessageLogged(Target target, String message,
  1921. int priority) {
  1922. BuildEvent event = new BuildEvent(target);
  1923. fireMessageLoggedEvent(event, message, priority);
  1924. }
  1925. /**
  1926. * Send a &quot;message logged&quot; task level event
  1927. * to the build listeners for this project.
  1928. *
  1929. * @param task The task generating the event.
  1930. * Must not be <code>null</code>.
  1931. * @param message The message to send. Should not be <code>null</code>.
  1932. * @param priority The priority of the message.
  1933. */
  1934. protected void fireMessageLogged(Task task, String message, int priority) {
  1935. BuildEvent event = new BuildEvent(task);
  1936. fireMessageLoggedEvent(event, message, priority);
  1937. }
  1938. /**
  1939. * Register a task as the current task for a thread.
  1940. * If the task is null, the thread's entry is removed.
  1941. *
  1942. * @param thread the thread on which the task is registered.
  1943. * @param task the task to be registered.
  1944. * @since Ant 1.5
  1945. */
  1946. public synchronized void registerThreadTask(Thread thread, Task task) {
  1947. if (task != null) {
  1948. threadTasks.put(thread, task);
  1949. threadGroupTasks.put(thread.getThreadGroup(), task);
  1950. } else {
  1951. threadTasks.remove(thread);
  1952. threadGroupTasks.remove(thread.getThreadGroup());
  1953. }
  1954. }
  1955. /**
  1956. * Get the current task associated with a thread, if any.
  1957. *
  1958. * @param thread the thread for which the task is required.
  1959. * @return the task which is currently registered for the given thread or
  1960. * null if no task is registered.
  1961. */
  1962. public Task getThreadTask(Thread thread) {
  1963. Task task = (Task) threadTasks.get(thread);
  1964. if (task == null) {
  1965. ThreadGroup group = thread.getThreadGroup();
  1966. while (task == null && group != null) {
  1967. task = (Task) threadGroupTasks.get(group);
  1968. group = group.getParent();
  1969. }
  1970. }
  1971. return task;
  1972. }
  1973. // Should move to a separate public class - and have API to add
  1974. // listeners, etc.
  1975. private static class AntRefTable extends Hashtable {
  1976. AntRefTable() {
  1977. super();
  1978. }
  1979. /** Returns the unmodified original object.
  1980. * This method should be called internally to
  1981. * get the &quot;real&quot; object.
  1982. * The normal get method will do the replacement
  1983. * of UnknownElement (this is similar with the JDNI
  1984. * refs behavior).
  1985. */
  1986. private Object getReal(Object key) {
  1987. return super.get(key);
  1988. }
  1989. /** Get method for the reference table.
  1990. * It can be used to hook dynamic references and to modify
  1991. * some references on the fly--for example for delayed
  1992. * evaluation.
  1993. *
  1994. * It is important to make sure that the processing that is
  1995. * done inside is not calling get indirectly.
  1996. *
  1997. * @param key lookup key.
  1998. * @return mapped value.
  1999. */
  2000. public Object get(Object key) {
  2001. //System.out.println("AntRefTable.get " + key);
  2002. Object o = getReal(key);
  2003. if (o instanceof UnknownElement) {
  2004. // Make sure that
  2005. UnknownElement ue = (UnknownElement) o;
  2006. ue.maybeConfigure();
  2007. o = ue.getRealThing();
  2008. }
  2009. return o;
  2010. }
  2011. }
  2012. /**
  2013. * Set a reference to this Project on the parameterized object.
  2014. * Need to set the project before other set/add elements
  2015. * are called.
  2016. * @param obj the object to invoke setProject(this) on.
  2017. */
  2018. public final void setProjectReference(final Object obj) {
  2019. if (obj instanceof ProjectComponent) {
  2020. ((ProjectComponent) obj).setProject(this);
  2021. return;
  2022. }
  2023. try {
  2024. Method method =
  2025. obj.getClass().getMethod(
  2026. "setProject", new Class[] {Project.class});
  2027. if (method != null) {
  2028. method.invoke(obj, new Object[] {this});
  2029. }
  2030. } catch (Throwable e) {
  2031. // ignore this if the object does not have
  2032. // a set project method or the method
  2033. // is private/protected.
  2034. }
  2035. }
  2036. }