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

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