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

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