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

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