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.

ProjectHelper.java 20 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "Ant" and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant;
  55. import java.io.BufferedReader;
  56. import java.io.File;
  57. import java.io.InputStream;
  58. import java.io.InputStreamReader;
  59. import java.util.Enumeration;
  60. import java.util.Hashtable;
  61. import java.util.Locale;
  62. import java.util.Vector;
  63. import org.apache.tools.ant.helper.ProjectHelper2;
  64. import org.apache.tools.ant.util.LoaderUtils;
  65. import org.xml.sax.AttributeList;
  66. import org.xml.sax.Attributes;
  67. /**
  68. * Configures a Project (complete with Targets and Tasks) based on
  69. * a XML build file. It'll rely on a plugin to do the actual processing
  70. * of the xml file.
  71. *
  72. * This class also provide static wrappers for common introspection.
  73. *
  74. * All helper plugins must provide backward compatiblity with the
  75. * original ant patterns, unless a different behavior is explicitely
  76. * specified. For example, if namespace is used on the &lt;project&gt; tag
  77. * the helper can expect the entire build file to be namespace-enabled.
  78. * Namespaces or helper-specific tags can provide meta-information to
  79. * the helper, allowing it to use new ( or different policies ).
  80. *
  81. * However, if no namespace is used the behavior should be exactly
  82. * identical with the default helper.
  83. *
  84. * @author duncan@x180.com
  85. */
  86. public class ProjectHelper {
  87. /**
  88. * Name of JVM system property which provides the name of the
  89. * ProjectHelper class to use.
  90. */
  91. public static final String HELPER_PROPERTY =
  92. "org.apache.tools.ant.ProjectHelper";
  93. /**
  94. * The service identifier in jars which provide Project Helper
  95. * implementations.
  96. */
  97. public static final String SERVICE_ID =
  98. "META-INF/services/org.apache.tools.ant.ProjectHelper";
  99. /**
  100. * Configures the project with the contents of the specified XML file.
  101. *
  102. * @param project The project to configure. Must not be <code>null</code>.
  103. * @param buildFile An XML file giving the project's configuration.
  104. * Must not be <code>null</code>.
  105. *
  106. * @deprecated Use the non-statuc parse method
  107. * @exception BuildException if the configuration is invalid or cannot
  108. * be read
  109. */
  110. public static void configureProject(Project project, File buildFile)
  111. throws BuildException {
  112. ProjectHelper helper = ProjectHelper.getProjectHelper();
  113. project.addReference("ant.projectHelper", helper);
  114. helper.parse(project, buildFile);
  115. }
  116. /** Default constructor */
  117. public ProjectHelper() {
  118. }
  119. // -------------------- Common properties --------------------
  120. // The following properties are required by import ( and other tasks
  121. // that read build files using ProjectHelper ).
  122. // A project helper may process multiple files. We'll keep track
  123. // of them - to avoid loops and to allow caching. The caching will
  124. // probably accelerate things like <antCall>.
  125. // The key is the absolute file, the value is a processed tree.
  126. // Since the tree is composed of UE and RC - it can be reused !
  127. // protected Hashtable processedFiles=new Hashtable();
  128. protected Vector importStack=new Vector();
  129. // Temporary - until we figure a better API
  130. /** EXPERIMENTAL WILL_CHANGE
  131. *
  132. */
  133. // public Hashtable getProcessedFiles() {
  134. // return processedFiles;
  135. // }
  136. /** EXPERIMENTAL WILL_CHANGE
  137. * Import stack.
  138. * Used to keep track of imported files. Error reporting should
  139. * display the import path.
  140. */
  141. public Vector getImportStack() {
  142. return importStack;
  143. }
  144. // -------------------- Parse method --------------------
  145. /**
  146. * Parses the project file, configuring the project as it goes.
  147. *
  148. * @param project The project for the resulting ProjectHelper to configure.
  149. * Must not be <code>null</code>.
  150. * @param source The source for XML configuration. A helper must support
  151. * at least File, for backward compatibility. Helpers may
  152. * support URL, InputStream, etc or specialized types.
  153. *
  154. * @since Ant1.5
  155. * @exception BuildException if the configuration is invalid or cannot
  156. * be read
  157. */
  158. public void parse(Project project, Object source) throws BuildException {
  159. throw new BuildException("ProjectHelper.parse() must be implemented "
  160. + "in a helper plugin " + this.getClass().getName());
  161. }
  162. /**
  163. * Discovers a project helper instance. Uses the same patterns
  164. * as JAXP, commons-logging, etc: a system property, a JDK1.3
  165. * service discovery, default.
  166. *
  167. * @return a ProjectHelper, either a custom implementation
  168. * if one is available and configured, or the default implementation
  169. * otherwise.
  170. *
  171. * @exception BuildException if a specified helper class cannot
  172. * be loaded/instantiated.
  173. */
  174. public static ProjectHelper getProjectHelper()
  175. throws BuildException {
  176. // Identify the class loader we will be using. Ant may be
  177. // in a webapp or embeded in a different app
  178. ProjectHelper helper = null;
  179. // First, try the system property
  180. String helperClass = System.getProperty(HELPER_PROPERTY);
  181. try {
  182. if (helperClass != null) {
  183. helper = newHelper(helperClass);
  184. }
  185. } catch (SecurityException e) {
  186. System.out.println("Unable to load ProjectHelper class \""
  187. + helperClass + " specified in system property "
  188. + HELPER_PROPERTY);
  189. }
  190. // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
  191. // automatically if in CLASSPATH, with the right META-INF/services.
  192. if (helper == null) {
  193. try {
  194. ClassLoader classLoader = LoaderUtils.getContextClassLoader();
  195. InputStream is = null;
  196. if (classLoader != null) {
  197. is = classLoader.getResourceAsStream(SERVICE_ID);
  198. }
  199. if (is == null) {
  200. is = ClassLoader.getSystemResourceAsStream(SERVICE_ID);
  201. }
  202. if (is != null) {
  203. // This code is needed by EBCDIC and other strange systems.
  204. // It's a fix for bugs reported in xerces
  205. InputStreamReader isr;
  206. try {
  207. isr = new InputStreamReader(is, "UTF-8");
  208. } catch (java.io.UnsupportedEncodingException e) {
  209. isr = new InputStreamReader(is);
  210. }
  211. BufferedReader rd = new BufferedReader(isr);
  212. String helperClassName = rd.readLine();
  213. rd.close();
  214. if (helperClassName != null &&
  215. !"".equals(helperClassName)) {
  216. helper = newHelper(helperClassName);
  217. }
  218. }
  219. } catch (Exception ex) {
  220. System.out.println("Unable to load ProjectHelper "
  221. + "from service \"" + SERVICE_ID);
  222. }
  223. }
  224. if (helper != null) {
  225. return helper;
  226. } else {
  227. try {
  228. // Default
  229. // return new ProjectHelperImpl();
  230. return new ProjectHelper2();
  231. } catch (Throwable e) {
  232. String message = "Unable to load default ProjectHelper due to "
  233. + e.getClass().getName() + ": " + e.getMessage();
  234. throw new BuildException(message, e);
  235. }
  236. }
  237. }
  238. /**
  239. * Creates a new helper instance from the name of the class.
  240. * It'll first try the thread class loader, then Class.forName()
  241. * will load from the same loader that loaded this class.
  242. *
  243. * @param helperClass The name of the class to create an instance
  244. * of. Must not be <code>null</code>.
  245. *
  246. * @return a new instance of the specified class.
  247. *
  248. * @exception BuildException if the class cannot be found or
  249. * cannot be appropriate instantiated.
  250. */
  251. private static ProjectHelper newHelper(String helperClass)
  252. throws BuildException {
  253. ClassLoader classLoader = LoaderUtils.getContextClassLoader();
  254. try {
  255. Class clazz = null;
  256. if (classLoader != null) {
  257. try {
  258. clazz = classLoader.loadClass(helperClass);
  259. } catch (ClassNotFoundException ex) {
  260. // try next method
  261. }
  262. }
  263. if (clazz == null) {
  264. clazz = Class.forName(helperClass);
  265. }
  266. return ((ProjectHelper) clazz.newInstance());
  267. } catch (Exception e) {
  268. throw new BuildException(e);
  269. }
  270. }
  271. /**
  272. * JDK1.1 compatible access to the context class loader.
  273. * Cut&paste from JAXP.
  274. *
  275. * @deprecated Use LoaderUtils.getContextClassLoader()
  276. * @return the current context class loader, or <code>null</code>
  277. * if the context class loader is unavailable.
  278. */
  279. public static ClassLoader getContextClassLoader() {
  280. if (!LoaderUtils.isContextLoaderAvailable()) {
  281. return null;
  282. }
  283. return LoaderUtils.getContextClassLoader();
  284. }
  285. // -------------------- Static utils, used by most helpers ----------------
  286. /**
  287. * Configures an object using an introspection handler.
  288. *
  289. * @param target The target object to be configured.
  290. * Must not be <code>null</code>.
  291. * @param attrs A list of attributes to configure within the target.
  292. * Must not be <code>null</code>.
  293. * @param project The project containing the target.
  294. * Must not be <code>null</code>.
  295. *
  296. * @deprecated Use IntrospectionHelper for each property
  297. * @exception BuildException if any of the attributes can't be handled by
  298. * the target
  299. */
  300. public static void configure(Object target, AttributeList attrs,
  301. Project project) throws BuildException {
  302. if (target instanceof TaskAdapter) {
  303. target = ((TaskAdapter) target).getProxy();
  304. }
  305. IntrospectionHelper ih =
  306. IntrospectionHelper.getHelper(target.getClass());
  307. project.addBuildListener(ih);
  308. for (int i = 0; i < attrs.getLength(); i++) {
  309. // reflect these into the target
  310. String value = replaceProperties(project, attrs.getValue(i),
  311. project.getProperties());
  312. try {
  313. ih.setAttribute(project, target,
  314. attrs.getName(i).toLowerCase(Locale.US), value);
  315. } catch (BuildException be) {
  316. // id attribute must be set externally
  317. if (!attrs.getName(i).equals("id")) {
  318. throw be;
  319. }
  320. }
  321. }
  322. }
  323. /**
  324. * Adds the content of #PCDATA sections to an element.
  325. *
  326. * @param project The project containing the target.
  327. * Must not be <code>null</code>.
  328. * @param target The target object to be configured.
  329. * Must not be <code>null</code>.
  330. * @param buf A character array of the text within the element.
  331. * Will not be <code>null</code>.
  332. * @param start The start element in the array.
  333. * @param count The number of characters to read from the array.
  334. *
  335. * @exception BuildException if the target object doesn't accept text
  336. */
  337. public static void addText(Project project, Object target, char[] buf,
  338. int start, int count) throws BuildException {
  339. addText(project, target, new String(buf, start, count));
  340. }
  341. /**
  342. * Adds the content of #PCDATA sections to an element.
  343. *
  344. * @param project The project containing the target.
  345. * Must not be <code>null</code>.
  346. * @param target The target object to be configured.
  347. * Must not be <code>null</code>.
  348. * @param text Text to add to the target.
  349. * May be <code>null</code>, in which case this
  350. * method call is a no-op.
  351. *
  352. * @exception BuildException if the target object doesn't accept text
  353. */
  354. public static void addText(Project project, Object target, String text)
  355. throws BuildException {
  356. if (text == null) {
  357. return;
  358. }
  359. if (target instanceof TaskAdapter) {
  360. target = ((TaskAdapter) target).getProxy();
  361. }
  362. IntrospectionHelper.getHelper(target.getClass()).addText(project,
  363. target, text);
  364. }
  365. /**
  366. * Stores a configured child element within its parent object.
  367. *
  368. * @param project Project containing the objects.
  369. * May be <code>null</code>.
  370. * @param parent Parent object to add child to.
  371. * Must not be <code>null</code>.
  372. * @param child Child object to store in parent.
  373. * Should not be <code>null</code>.
  374. * @param tag Name of element which generated the child.
  375. * May be <code>null</code>, in which case
  376. * the child is not stored.
  377. */
  378. public static void storeChild(Project project, Object parent,
  379. Object child, String tag) {
  380. IntrospectionHelper ih
  381. = IntrospectionHelper.getHelper(parent.getClass());
  382. ih.storeElement(project, parent, child, tag);
  383. }
  384. /**
  385. * Replaces <code>${xxx}</code> style constructions in the given value with
  386. * the string value of the corresponding properties.
  387. *
  388. * @param project The project containing the properties to replace.
  389. * Must not be <code>null</code>.
  390. *
  391. * @param value The string to be scanned for property references.
  392. * May be <code>null</code>.
  393. *
  394. * @exception BuildException if the string contains an opening
  395. * <code>${</code> without a closing
  396. * <code>}</code>
  397. * @return the original string with the properties replaced, or
  398. * <code>null</code> if the original string is <code>null</code>.
  399. *
  400. * @deprecated Use project.replaceProperties()
  401. * @since 1.5
  402. */
  403. public static String replaceProperties(Project project, String value)
  404. throws BuildException {
  405. // needed since project properties are not accessible
  406. return project.replaceProperties(value);
  407. }
  408. /**
  409. * Replaces <code>${xxx}</code> style constructions in the given value
  410. * with the string value of the corresponding data types.
  411. *
  412. * @param project The container project. This is used solely for
  413. * logging purposes. Must not be <code>null</code>.
  414. * @param value The string to be scanned for property references.
  415. * May be <code>null</code>, in which case this
  416. * method returns immediately with no effect.
  417. * @param keys Mapping (String to String) of property names to their
  418. * values. Must not be <code>null</code>.
  419. *
  420. * @exception BuildException if the string contains an opening
  421. * <code>${</code> without a closing
  422. * <code>}</code>
  423. * @return the original string with the properties replaced, or
  424. * <code>null</code> if the original string is <code>null</code>.
  425. * @deprecated Use PropertyHelper
  426. */
  427. public static String replaceProperties(Project project, String value,
  428. Hashtable keys) throws BuildException
  429. {
  430. PropertyHelper ph=PropertyHelper.getPropertyHelper(project);
  431. return ph.replaceProperties( null, value, keys);
  432. }
  433. /**
  434. * Parses a string containing <code>${xxx}</code> style property
  435. * references into two lists. The first list is a collection
  436. * of text fragments, while the other is a set of string property names.
  437. * <code>null</code> entries in the first list indicate a property
  438. * reference from the second list.
  439. *
  440. * @param value Text to parse. Must not be <code>null</code>.
  441. * @param fragments List to add text fragments to.
  442. * Must not be <code>null</code>.
  443. * @param propertyRefs List to add property names to.
  444. * Must not be <code>null</code>.
  445. *
  446. * @deprecated Use PropertyHelper
  447. * @exception BuildException if the string contains an opening
  448. * <code>${</code> without a closing
  449. * <code>}</code>
  450. */
  451. public static void parsePropertyString(String value, Vector fragments,
  452. Vector propertyRefs)
  453. throws BuildException
  454. {
  455. PropertyHelper.parsePropertyStringDefault(value, fragments,
  456. propertyRefs);
  457. }
  458. //end class
  459. }