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 15 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  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 "The Jakarta Project", "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.File;
  56. import java.io.FileInputStream;
  57. import java.io.FileNotFoundException;
  58. import java.io.IOException;
  59. import java.io.InputStream;
  60. import java.io.BufferedReader;
  61. import java.io.InputStreamReader;
  62. import java.util.Hashtable;
  63. import java.util.Vector;
  64. import java.util.Enumeration;
  65. import java.util.Locale;
  66. import java.lang.reflect.InvocationTargetException;
  67. import java.lang.reflect.Method;
  68. import org.xml.sax.AttributeList;
  69. /**
  70. * Configures a Project (complete with Targets and Tasks) based on
  71. * a XML build file. It'll rely on a plugin to do the actual processing
  72. * of the xml file.
  73. *
  74. * This class also provide static wrappers for common introspection.
  75. *
  76. * All helper plugins must provide backward compatiblity with the
  77. * original ant patterns, unless a different behavior is explicitely
  78. * specified. For example, if namespace is used on the <project> tag
  79. * the helper can expect the entire build file to be namespace-enabled.
  80. * Namespaces or helper-specific tags can provide meta-information to
  81. * the helper, allowing it to use new ( or different policies ).
  82. *
  83. * However, if no namespace is used the behavior should be exactly
  84. * identical with the default helper.
  85. *
  86. * @author duncan@x180.com
  87. */
  88. public /*abstract*/ class ProjectHelper {
  89. /**
  90. * Configures the Project with the contents of the specified XML file.
  91. * ( should it be deprecated ? Using getProjectHelper(), parse()
  92. * is cleaner )
  93. */
  94. public static void configureProject(Project project, File buildFile)
  95. throws BuildException
  96. {
  97. ProjectHelper helper=ProjectHelper.getProjectHelper();
  98. helper.parse(project, buildFile);
  99. }
  100. public ProjectHelper() {
  101. }
  102. /**
  103. * Constructs a new Ant parser for the specified XML file.
  104. * @deprecated Use the plugin mechanism instead.
  105. */
  106. private ProjectHelper(Project project, File buildFile) {
  107. // this.project = project;
  108. // this.buildFile = new File(buildFile.getAbsolutePath());
  109. // buildFileParent = new File(this.buildFile.getParent());
  110. }
  111. public Project createProject(ClassLoader coreLoader) {
  112. return new Project();
  113. }
  114. /**
  115. * Process an input source for the project.
  116. *
  117. * All processors must support at least File sources. It is usefull to also support
  118. * InputSource - this allows the input to come from a non-filesystem source
  119. * (like input stream of a POST, or a soap body ).
  120. */
  121. public /*abstract*/ void parse(Project project, Object source)
  122. throws BuildException
  123. {
  124. throw new BuildException("You must use a real ProjectHelper implementation");
  125. }
  126. /* -------------------- Helper discovery -------------------- */
  127. public static final String HELPER_PROPERTY =
  128. "org.apache.tools.ant.ProjectHelper";
  129. public static final String SERVICE_ID =
  130. "/META-INF/services/org.apache.tools.ant.ProjectHelper";
  131. /** Discover a project helper instance.
  132. */
  133. public static ProjectHelper getProjectHelper()
  134. throws BuildException
  135. {
  136. // Identify the class loader we will be using. Ant may be
  137. // in a webapp or embeded in a different app
  138. ClassLoader classLoader = getContextClassLoader();
  139. ProjectHelper helper=null;
  140. // First, try the system property
  141. try {
  142. String helperClass = System.getProperty(HELPER_PROPERTY);
  143. if (helperClass != null) {
  144. helper = newHelper(helperClass, classLoader);
  145. }
  146. } catch (SecurityException e) {
  147. // It's ok, we'll try next option
  148. ;
  149. }
  150. // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
  151. // automatically if in CLASSPATH, with the right META-INF/services.
  152. if( helper==null ) {
  153. try {
  154. InputStream is=null;
  155. if (classLoader == null) {
  156. is=ClassLoader.getSystemResourceAsStream( SERVICE_ID );
  157. } else {
  158. is=classLoader.getResourceAsStream( SERVICE_ID );
  159. }
  160. if( is != null ) {
  161. // This code is needed by EBCDIC and other strange systems.
  162. // It's a fix for bugs reported in xerces
  163. BufferedReader rd;
  164. try {
  165. rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
  166. } catch (java.io.UnsupportedEncodingException e) {
  167. rd = new BufferedReader(new InputStreamReader(is));
  168. }
  169. String helperClassName = rd.readLine();
  170. rd.close();
  171. if (helperClassName != null &&
  172. ! "".equals(helperClassName)) {
  173. helper= newHelper( helperClassName, classLoader );
  174. }
  175. }
  176. } catch( Exception ex ) {
  177. ;
  178. }
  179. }
  180. // Default
  181. return new ProjectHelperImpl();
  182. }
  183. private static ProjectHelper newHelper(String helperClass,
  184. ClassLoader classLoader)
  185. throws BuildException
  186. {
  187. try {
  188. Class clazz = null;
  189. if (classLoader == null) {
  190. clazz = Class.forName(helperClass);
  191. } else {
  192. clazz = classLoader.loadClass(helperClass);
  193. }
  194. return ((ProjectHelper) clazz.newInstance());
  195. } catch (Exception e) {
  196. throw new BuildException(e);
  197. }
  198. }
  199. /**
  200. */
  201. public static ClassLoader getContextClassLoader()
  202. throws BuildException
  203. {
  204. // Are we running on a JDK 1.2 or later system?
  205. Method method = null;
  206. try {
  207. method = Thread.class.getMethod("getContextClassLoader", null);
  208. } catch (NoSuchMethodException e) {
  209. // we are running on JDK 1.1
  210. return null;
  211. }
  212. // Get the thread context class loader (if there is one)
  213. ClassLoader classLoader = null;
  214. try {
  215. classLoader = (ClassLoader)
  216. method.invoke(Thread.currentThread(), null);
  217. } catch (IllegalAccessException e) {
  218. throw new BuildException
  219. ("Unexpected IllegalAccessException", e);
  220. } catch (InvocationTargetException e) {
  221. throw new BuildException
  222. ("Unexpected InvocationTargetException", e);
  223. }
  224. // Return the selected class loader
  225. return (classLoader);
  226. }
  227. /* -------------------- Common utilities and wrappers -------------------- */
  228. /** Configure a java object using ant's rules.
  229. */
  230. public static void configure(Object target, AttributeList attrs,
  231. Project project) throws BuildException {
  232. TaskAdapter adapter=null;
  233. if( target instanceof TaskAdapter ) {
  234. adapter=(TaskAdapter)target;
  235. target=adapter.getProxy();
  236. }
  237. IntrospectionHelper ih =
  238. IntrospectionHelper.getHelper(target.getClass());
  239. if( adapter != null )
  240. adapter.setIntrospectionHelper( ih );
  241. // XXX What's that ?
  242. project.addBuildListener(ih);
  243. for (int i = 0; i < attrs.getLength(); i++) {
  244. // reflect these into the target
  245. String value=replaceProperties(project, attrs.getValue(i),
  246. project.getProperties() );
  247. String name=attrs.getName(i).toLowerCase(Locale.US);
  248. try {
  249. if (adapter!=null ) {
  250. adapter.setAttribute( name, value );
  251. } else {
  252. ih.setAttribute(project, target,
  253. name, value);
  254. }
  255. } catch (BuildException be) {
  256. // id attribute must be set externally
  257. // XXX Shuldn't it be 'name' ( i.e. lower-cased ) ?
  258. if (!attrs.getName(i).equals("id")) {
  259. throw be;
  260. }
  261. }
  262. }
  263. }
  264. /**
  265. * Adds the content of #PCDATA sections to an element.
  266. */
  267. public static void addText(Project project, Object target, char[] buf, int start, int end)
  268. throws BuildException {
  269. addText(project, target, new String(buf, start, end));
  270. }
  271. /**
  272. * Adds the content of #PCDATA sections to an element.
  273. */
  274. public static void addText(Project project, Object target, String text)
  275. throws BuildException {
  276. if (text == null ) {
  277. return;
  278. }
  279. if(target instanceof TaskAdapter) {
  280. target = ((TaskAdapter) target).getProxy();
  281. }
  282. IntrospectionHelper.getHelper(target.getClass()).addText(project, target, text);
  283. }
  284. /**
  285. * Stores a configured child element into its parent object
  286. */
  287. public static void storeChild(Project project, Object parent, Object child, String tag) {
  288. IntrospectionHelper ih = IntrospectionHelper.getHelper(parent.getClass());
  289. ih.storeElement(project, parent, child, tag);
  290. }
  291. /**
  292. * Replace ${} style constructions in the given value with the string value of
  293. * the corresponding data types.
  294. *
  295. * @param value the string to be scanned for property references.
  296. * @since 1.5
  297. */
  298. public static String replaceProperties(Project project, String value)
  299. throws BuildException {
  300. return project.replaceProperties(value);
  301. }
  302. /**
  303. * Replace ${} style constructions in the given value with the string value of
  304. * the corresponding data types.
  305. *
  306. * @param value the string to be scanned for property references.
  307. */
  308. public static String replaceProperties(Project project, String value, Hashtable keys)
  309. throws BuildException {
  310. if (value == null) {
  311. return null;
  312. }
  313. Vector fragments = new Vector();
  314. Vector propertyRefs = new Vector();
  315. parsePropertyString(value, fragments, propertyRefs);
  316. StringBuffer sb = new StringBuffer();
  317. Enumeration i = fragments.elements();
  318. Enumeration j = propertyRefs.elements();
  319. while (i.hasMoreElements()) {
  320. String fragment = (String)i.nextElement();
  321. if (fragment == null) {
  322. String propertyName = (String)j.nextElement();
  323. if (!keys.containsKey(propertyName)) {
  324. project.log("Property ${" + propertyName + "} has not been set", Project.MSG_VERBOSE);
  325. }
  326. fragment = (keys.containsKey(propertyName)) ? (String) keys.get(propertyName)
  327. : "${" + propertyName + "}";
  328. }
  329. sb.append(fragment);
  330. }
  331. return sb.toString();
  332. }
  333. /**
  334. * This method will parse a string containing ${value} style
  335. * property values into two lists. The first list is a collection
  336. * of text fragments, while the other is a set of string property names
  337. * null entries in the first list indicate a property reference from the
  338. * second list.
  339. */
  340. public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs)
  341. throws BuildException {
  342. int prev = 0;
  343. int pos;
  344. while ((pos = value.indexOf("$", prev)) >= 0) {
  345. if (pos > 0) {
  346. fragments.addElement(value.substring(prev, pos));
  347. }
  348. if( pos == (value.length() - 1)) {
  349. fragments.addElement("$");
  350. prev = pos + 1;
  351. }
  352. else if (value.charAt(pos + 1) != '{' ) {
  353. fragments.addElement(value.substring(pos + 1, pos + 2));
  354. prev = pos + 2;
  355. } else {
  356. int endName = value.indexOf('}', pos);
  357. if (endName < 0) {
  358. throw new BuildException("Syntax error in property: "
  359. + value );
  360. }
  361. String propertyName = value.substring(pos + 2, endName);
  362. fragments.addElement(null);
  363. propertyRefs.addElement(propertyName);
  364. prev = endName + 1;
  365. }
  366. }
  367. if (prev < value.length()) {
  368. fragments.addElement(value.substring(prev));
  369. }
  370. }
  371. }