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

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