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.

Definer.java 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2001-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.taskdefs;
  55. import java.io.File;
  56. import java.io.FileInputStream;
  57. import java.io.IOException;
  58. import java.io.InputStream;
  59. import java.util.Enumeration;
  60. import java.util.Properties;
  61. import org.apache.tools.ant.AntClassLoader;
  62. import org.apache.tools.ant.BuildException;
  63. import org.apache.tools.ant.Project;
  64. import org.apache.tools.ant.Task;
  65. import org.apache.tools.ant.types.Path;
  66. import org.apache.tools.ant.types.Reference;
  67. /**
  68. * Base class for Taskdef and Typedef - does all the classpath
  69. * handling and and class loading.
  70. *
  71. * @author Costin Manolache
  72. * @author <a href="stefan.bodewig@epost.de">Stefan Bodewig</a>
  73. *
  74. * @since Ant 1.4
  75. */
  76. public abstract class Definer extends Task {
  77. private String name;
  78. private String value;
  79. private Path classpath;
  80. private File file;
  81. private String resource;
  82. private boolean reverseLoader = false;
  83. private String loaderId = null;
  84. private String classpathId = null;
  85. private static final String REUSE_LOADER_REF = "ant.reuse.loader";
  86. /**
  87. * @deprecated stop using this attribute
  88. * @ant.attribute ignore="true"
  89. */
  90. public void setReverseLoader(boolean reverseLoader) {
  91. this.reverseLoader = reverseLoader;
  92. log("The reverseloader attribute is DEPRECATED. It will be removed",
  93. Project.MSG_WARN);
  94. }
  95. /**
  96. * Set the classpath to be used when searching for component being defined
  97. *
  98. * @param classpath an Ant Path object containing the classpath.
  99. */
  100. public void setClasspath(Path classpath) {
  101. if (this.classpath == null) {
  102. this.classpath = classpath;
  103. } else {
  104. this.classpath.append(classpath);
  105. }
  106. }
  107. /**
  108. * Create the classpath to be used when searching for component being defined
  109. */
  110. public Path createClasspath() {
  111. if (this.classpath == null) {
  112. this.classpath = new Path(getProject());
  113. }
  114. return this.classpath.createPath();
  115. }
  116. /**
  117. * reference to a classpath to use when loading the files.
  118. * To actually share the same loader, set loaderref as well
  119. */
  120. public void setClasspathRef(Reference r) {
  121. classpathId=r.getRefId();
  122. createClasspath().setRefid(r);
  123. }
  124. /**
  125. * Use the reference to locate the loader. If the loader is not
  126. * found, taskdef will use the specified classpath and register it
  127. * with the specified name.
  128. *
  129. * This allow multiple taskdef/typedef to use the same class loader,
  130. * so they can be used together. It eliminate the need to
  131. * put them in the CLASSPATH.
  132. *
  133. * @since Ant 1.5
  134. */
  135. public void setLoaderRef(Reference r) {
  136. loaderId = r.getRefId();
  137. }
  138. public void execute() throws BuildException {
  139. AntClassLoader al = createLoader();
  140. if (file == null && resource == null) {
  141. // simple case - one definition
  142. if (name == null || value == null) {
  143. String msg = "name or classname attributes of "
  144. + getTaskName() + " element "
  145. + "are undefined";
  146. throw new BuildException(msg);
  147. }
  148. addDefinition(al, name, value);
  149. } else {
  150. InputStream is = null;
  151. try {
  152. if (name != null || value != null) {
  153. String msg = "You must not specify name or value "
  154. + "together with file or resource.";
  155. throw new BuildException(msg, getLocation());
  156. }
  157. if (file != null && resource != null) {
  158. String msg = "You must not specify both, file and "
  159. + "resource.";
  160. throw new BuildException(msg, getLocation());
  161. }
  162. Properties props = new Properties();
  163. if (file != null) {
  164. log("Loading definitions from file " + file,
  165. Project.MSG_VERBOSE);
  166. is = new FileInputStream(file);
  167. if (is == null) {
  168. log("Could not load definitions from file " + file
  169. + ". It doesn\'t exist.", Project.MSG_WARN);
  170. }
  171. }
  172. if (resource != null) {
  173. log("Loading definitions from resource " + resource,
  174. Project.MSG_VERBOSE);
  175. is = al.getResourceAsStream(resource);
  176. if (is == null) {
  177. log("Could not load definitions from resource "
  178. + resource + ". It could not be found.",
  179. Project.MSG_WARN);
  180. }
  181. }
  182. if (is != null) {
  183. props.load(is);
  184. Enumeration keys = props.keys();
  185. while (keys.hasMoreElements()) {
  186. String n = (String) keys.nextElement();
  187. String v = props.getProperty(n);
  188. addDefinition(al, n, v);
  189. }
  190. }
  191. } catch (IOException ex) {
  192. throw new BuildException(ex, getLocation());
  193. } finally {
  194. if (is != null) {
  195. try {
  196. is.close();
  197. } catch (IOException e) {}
  198. }
  199. }
  200. }
  201. }
  202. /**
  203. * create the classloader then hand the definition off to the subclass;
  204. * @throws BuildException when the class wont load for any reason
  205. */
  206. private void addDefinition(ClassLoader al, String name, String value)
  207. throws BuildException {
  208. try {
  209. Class c = al.loadClass(value);
  210. AntClassLoader.initializeClass(c);
  211. addDefinition(name, c);
  212. } catch (ClassNotFoundException cnfe) {
  213. String msg = getTaskName() + " class " + value
  214. + " cannot be found";
  215. throw new BuildException(msg, cnfe, getLocation());
  216. } catch (NoClassDefFoundError ncdfe) {
  217. String msg = getTaskName() + " class " + value
  218. + " cannot be found";
  219. throw new BuildException(msg, ncdfe, getLocation());
  220. }
  221. }
  222. /**
  223. * create a classloader for this definition
  224. */
  225. private AntClassLoader createLoader() {
  226. // magic property
  227. if (getProject().getProperty(REUSE_LOADER_REF) != null) {
  228. // Generate the 'reuse' name automatically from the reference.
  229. // This allows <taskdefs> that work on both ant1.4 and ant1.5.
  230. // ( in 1.4 it'll require the task/type to be in classpath if they
  231. // are used togheter ).
  232. if (loaderId == null && classpathId != null) {
  233. loaderId = "ant.loader." + classpathId;
  234. }
  235. }
  236. // If a loader has been set ( either by loaderRef or magic property )
  237. if (loaderId != null) {
  238. Object reusedLoader = getProject().getReference(loaderId);
  239. if (reusedLoader != null) {
  240. if (reusedLoader instanceof AntClassLoader) {
  241. return (AntClassLoader)reusedLoader;
  242. }
  243. // In future the reference object may be the <loader> type
  244. // if( reusedLoader instanceof Loader ) {
  245. // return ((Loader)reusedLoader).getLoader(project);
  246. // }
  247. }
  248. }
  249. AntClassLoader al = null;
  250. if (classpath != null) {
  251. al = new AntClassLoader(getProject(), classpath, !reverseLoader);
  252. } else {
  253. al = new AntClassLoader(getProject(), Path.systemClasspath,
  254. !reverseLoader);
  255. }
  256. // need to load Task via system classloader or the new
  257. // task we want to define will never be a Task but always
  258. // be wrapped into a TaskAdapter.
  259. al.addSystemPackageRoot("org.apache.tools.ant");
  260. // If the loader is new, record it for future uses by other
  261. // task/typedefs
  262. if (loaderId != null) {
  263. if (getProject().getReference(loaderId) == null) {
  264. getProject().addReference(loaderId, al);
  265. }
  266. }
  267. return al;
  268. }
  269. /**
  270. * Name of the property file to load
  271. * ant name/classname pairs from.
  272. */
  273. public void setFile(File file) {
  274. this.file = file;
  275. }
  276. /**
  277. * Name of the property resource to load
  278. * ant name/classname pairs from.
  279. */
  280. public void setResource(String res) {
  281. this.resource = res;
  282. }
  283. /**
  284. * Name of the property resource to load
  285. * ant name/classname pairs from.
  286. */
  287. public void setName(String name) {
  288. this.name = name;
  289. }
  290. /**
  291. * Returns the classname of the object we are defining.
  292. * May be <code>null</code>.
  293. */
  294. public String getClassname() {
  295. return value;
  296. }
  297. /**
  298. * The full class name of the object being defined.
  299. * Required, unless file or resource have
  300. * been specified.
  301. */
  302. public void setClassname(String v) {
  303. value = v;
  304. }
  305. /**
  306. * This must be implemented by subclasses; it is the callback
  307. * they will get to add a new definition of their type.
  308. */
  309. protected abstract void addDefinition(String name, Class c);
  310. }