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

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