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.

ComponentHelper.java 38 kB

PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
PR: 19897 Submitted by: Peter Reilly This patch adds the add(Type) to the introspection rules and updates ConditionBase, FilterChain, Path, SelectorBase and TokenFilter to use the new introspection rule. ========================================= = Changed Files ========================================= src/main/org/apache/tools/ant/ProjectHelper.java add two methods used by introspection - getComponentClass and createComponent src/main/org/apache/tools/ant/IntrospectionHelper.java implement addTypeMethods add(Type) src/main/org/apache/tools/ant/filters/TokenFilter.java get TokenFilter to use add(Type) instead of dynamicconfigurator make all nested classes ProjectComponents src/main/org/apache/tools/ant/taskdefs/Delete.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/MatchingTask.java implement an add(FileSelector) method src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java add an add(Condition) method to demostrate use of add(Type) method src/main/org/apache/tools/ant/types/AbstractFileSet.java implement add(FileSelector) src/main/org/apache/tools/ant/types/FilterChain.java use add(ChainableReader) instead of DynamicConfigurator src/main/org/apache/tools/ant/types/Path.java add an add(Path) method src/main/org/apache/tools/ant/types/optional/ScriptFilter.java remove set/get project as parent imlements them now src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java implement the add(FileSelector) method src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java add an add(FileSelector) method ========================================= = New Files ========================================= src/etc/testcases/types/addtype.xml testcases for addtype src/testcases/org/apache/tools/ant/types/AddTypeTest.java test cases for add type git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274635 13f79535-47bb-0310-9956-ffa450edef68
23 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. /*
  2. * Copyright 2003-2006 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import java.util.Enumeration;
  19. import java.util.Hashtable;
  20. import java.util.HashSet;
  21. import java.util.Iterator;
  22. import java.util.Properties;
  23. import java.util.Set;
  24. import java.util.Stack;
  25. import java.util.Vector;
  26. import java.io.InputStream;
  27. import java.io.IOException;
  28. import java.io.File;
  29. import java.io.StringWriter;
  30. import java.io.PrintWriter;
  31. import java.lang.ref.WeakReference;
  32. import java.lang.reflect.Modifier;
  33. import java.lang.reflect.InvocationTargetException;
  34. import org.apache.tools.ant.taskdefs.Typedef;
  35. import org.apache.tools.ant.taskdefs.Definer;
  36. import org.apache.tools.ant.launch.Launcher;
  37. /**
  38. * Component creation and configuration.
  39. *
  40. * The class is based around handing component
  41. * definitions in an AntTypeTable.
  42. *
  43. * The old task/type methods have been kept
  44. * for backward compatibly.
  45. * Project will just delegate its calls to this class.
  46. *
  47. * A very simple hook mechanism is provided that allows users to plug
  48. * in custom code. It is also possible to replace the default behavior
  49. * ( for example in an app embedding ant )
  50. *
  51. * @since Ant1.6
  52. */
  53. public class ComponentHelper {
  54. /** Map from component name to anttypedefinition */
  55. private AntTypeTable antTypeTable;
  56. /** Map of tasks generated from antTypeTable */
  57. private Hashtable taskClassDefinitions = new Hashtable();
  58. /** flag to rebuild taskClassDefinitions */
  59. private boolean rebuildTaskClassDefinitions = true;
  60. /** Map of types generated from antTypeTable */
  61. private Hashtable typeClassDefinitions = new Hashtable();
  62. /** flag to rebuild typeClassDefinitions */
  63. private boolean rebuildTypeClassDefinitions = true;
  64. /** Set of namespaces that have been checked for antlibs */
  65. private Set checkedNamespaces = new HashSet();
  66. /**
  67. * Stack of antlib contexts used to resolve definitions while
  68. * processing antlib
  69. */
  70. private Stack antLibStack = new Stack();
  71. /** current antlib uri */
  72. private String antLibCurrentUri = null;
  73. /**
  74. * Map from task names to vectors of created tasks
  75. * (String to Vector of Task). This is used to invalidate tasks if
  76. * the task definition changes.
  77. */
  78. private Hashtable createdTasks = new Hashtable();
  79. /**
  80. * this does not appear to be used anywhere in the Ant codebase
  81. * even via its accessors
  82. */
  83. private ComponentHelper next;
  84. /**
  85. * Project that owns a component helper
  86. */
  87. private Project project;
  88. /**
  89. * Error string when the file taskdefs/defaults.properties cannot be found
  90. */
  91. private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load default task list";
  92. /**
  93. * Error string when the typedefs/defaults.properties cannot be found
  94. */
  95. private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list";
  96. /**
  97. * reference under which we register ourselves with a project -{@value}
  98. */
  99. public static final String COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper";
  100. /**
  101. * string used to control build.syspath policy {@value}
  102. */
  103. private static final String BUILD_SYSCLASSPATH_ONLY = "only";
  104. /**
  105. * special name of ant's property task -{@value}. There is some
  106. * contrived work here to enable this early.
  107. */
  108. private static final String ANT_PROPERTY_TASK = "property";
  109. /**
  110. * Find a project component for a specific project, creating
  111. * it if it does not exist.
  112. * @param project the project.
  113. * @return the project component for a specific project.
  114. */
  115. public static ComponentHelper getComponentHelper(Project project) {
  116. // Singleton for now, it may change ( per/classloader )
  117. ComponentHelper ph = (ComponentHelper) project.getReference(
  118. COMPONENT_HELPER_REFERENCE);
  119. if (ph != null) {
  120. return ph;
  121. }
  122. ph = new ComponentHelper();
  123. ph.setProject(project);
  124. project.addReference(COMPONENT_HELPER_REFERENCE, ph);
  125. return ph;
  126. }
  127. /**
  128. * Creates a new ComponentHelper instance.
  129. */
  130. protected ComponentHelper() {
  131. }
  132. /**
  133. * Set the next chained component helper.
  134. *
  135. * @param next the next chained component helper.
  136. */
  137. public void setNext(ComponentHelper next) {
  138. this.next = next;
  139. }
  140. /**
  141. * Get the next chained component helper.
  142. *
  143. * @return the next chained component helper.
  144. */
  145. public ComponentHelper getNext() {
  146. return next;
  147. }
  148. /**
  149. * Sets the project for this component helper.
  150. *
  151. * @param project the project for this helper.
  152. */
  153. public void setProject(Project project) {
  154. this.project = project;
  155. antTypeTable = new AntTypeTable(project);
  156. }
  157. /**
  158. * Used with creating child projects. Each child
  159. * project inherits the component definitions
  160. * from its parent.
  161. * @param helper the component helper of the parent project.
  162. */
  163. public void initSubProject(ComponentHelper helper) {
  164. // add the types of the parent project
  165. AntTypeTable typeTable = helper.antTypeTable;
  166. for (Iterator i = typeTable.values().iterator(); i.hasNext();) {
  167. AntTypeDefinition def = (AntTypeDefinition) i.next();
  168. antTypeTable.put(def.getName(), def);
  169. }
  170. // add the parsed namespaces of the parent project
  171. for (Iterator i = helper.checkedNamespaces.iterator(); i.hasNext();) {
  172. checkedNamespaces.add(i.next());
  173. }
  174. }
  175. /**
  176. * Factory method to create the components.
  177. *
  178. * This should be called by UnknownElement.
  179. *
  180. * @param ue The Unknown Element creating this component.
  181. * @param ns Namespace URI. Also available as ue.getNamespace().
  182. * @param componentType The component type,
  183. * Also available as ue.getComponentName().
  184. * @return the created component.
  185. * @throws BuildException if an error occurs.
  186. */
  187. public Object createComponent(UnknownElement ue,
  188. String ns,
  189. String componentType)
  190. throws BuildException {
  191. Object component = createComponent(componentType);
  192. if (component instanceof Task) {
  193. Task task = (Task) component;
  194. task.setLocation(ue.getLocation());
  195. task.setTaskType(componentType);
  196. task.setTaskName(ue.getTaskName());
  197. task.setOwningTarget(ue.getOwningTarget());
  198. task.init();
  199. addCreatedTask(componentType, task);
  200. }
  201. return component;
  202. }
  203. /**
  204. * Create an object for a component.
  205. *
  206. * @param componentName the name of the component, if
  207. * the component is in a namespace, the
  208. * name is prefixed with the namespace uri and ":".
  209. * @return the class if found or null if not.
  210. */
  211. public Object createComponent(String componentName) {
  212. AntTypeDefinition def = getDefinition(componentName);
  213. return (def == null) ? null : def.create(project);
  214. }
  215. /**
  216. * Return the class of the component name.
  217. *
  218. * @param componentName the name of the component, if
  219. * the component is in a namespace, the
  220. * name is prefixed with the namespace uri and ":".
  221. * @return the class if found or null if not.
  222. */
  223. public Class getComponentClass(String componentName) {
  224. AntTypeDefinition def = getDefinition(componentName);
  225. return (def == null) ? null : def.getExposedClass(project);
  226. }
  227. /**
  228. * Return the antTypeDefinition for a componentName.
  229. * @param componentName the name of the component.
  230. * @return the ant definition or null if not present.
  231. */
  232. public AntTypeDefinition getDefinition(String componentName) {
  233. checkNamespace(componentName);
  234. return antTypeTable.getDefinition(componentName);
  235. }
  236. /**
  237. * This method is initialization code implementing the original ant component
  238. * loading from /org/apache/tools/ant/taskdefs/default.properties
  239. * and /org/apache/tools/ant/types/default.properties.
  240. */
  241. public void initDefaultDefinitions() {
  242. initTasks();
  243. initTypes();
  244. }
  245. /**
  246. * Adds a new task definition to the project.
  247. * Attempting to override an existing definition with an
  248. * equivalent one (i.e. with the same classname) results in
  249. * a verbose log message. Attempting to override an existing definition
  250. * with a different one results in a warning log message and
  251. * invalidates any tasks which have already been created with the
  252. * old definition.
  253. *
  254. * @param taskName The name of the task to add.
  255. * Must not be <code>null</code>.
  256. * @param taskClass The full name of the class implementing the task.
  257. * Must not be <code>null</code>.
  258. *
  259. * @exception BuildException if the class is unsuitable for being an Ant
  260. * task. An error level message is logged before
  261. * this exception is thrown.
  262. *
  263. * @see #checkTaskClass(Class)
  264. */
  265. public void addTaskDefinition(String taskName, Class taskClass) {
  266. checkTaskClass(taskClass);
  267. AntTypeDefinition def = new AntTypeDefinition();
  268. def.setName(taskName);
  269. def.setClassLoader(taskClass.getClassLoader());
  270. def.setClass(taskClass);
  271. def.setAdapterClass(TaskAdapter.class);
  272. def.setClassName(taskClass.getName());
  273. def.setAdaptToClass(Task.class);
  274. updateDataTypeDefinition(def);
  275. }
  276. /**
  277. * Checks whether or not a class is suitable for serving as Ant task.
  278. * Ant task implementation classes must be public, concrete, and have
  279. * a no-arg constructor.
  280. *
  281. * @param taskClass The class to be checked.
  282. * Must not be <code>null</code>.
  283. *
  284. * @exception BuildException if the class is unsuitable for being an Ant
  285. * task. An error level message is logged before
  286. * this exception is thrown.
  287. */
  288. public void checkTaskClass(final Class taskClass) throws BuildException {
  289. if (!Modifier.isPublic(taskClass.getModifiers())) {
  290. final String message = taskClass + " is not public";
  291. project.log(message, Project.MSG_ERR);
  292. throw new BuildException(message);
  293. }
  294. if (Modifier.isAbstract(taskClass.getModifiers())) {
  295. final String message = taskClass + " is abstract";
  296. project.log(message, Project.MSG_ERR);
  297. throw new BuildException(message);
  298. }
  299. try {
  300. taskClass.getConstructor((Class[]) null);
  301. // don't have to check for public, since
  302. // getConstructor finds public constructors only.
  303. } catch (NoSuchMethodException e) {
  304. final String message = "No public no-arg constructor in "
  305. + taskClass;
  306. project.log(message, Project.MSG_ERR);
  307. throw new BuildException(message);
  308. }
  309. if (!Task.class.isAssignableFrom(taskClass)) {
  310. TaskAdapter.checkTaskClass(taskClass, project);
  311. }
  312. }
  313. /**
  314. * Returns the current task definition hashtable. The returned hashtable is
  315. * "live" and so should not be modified.
  316. *
  317. * @return a map of from task name to implementing class
  318. * (String to Class).
  319. */
  320. public Hashtable getTaskDefinitions() {
  321. synchronized (taskClassDefinitions) {
  322. synchronized (antTypeTable) {
  323. if (rebuildTaskClassDefinitions) {
  324. taskClassDefinitions.clear();
  325. for (Iterator i = antTypeTable.keySet().iterator();
  326. i.hasNext();) {
  327. String name = (String) i.next();
  328. Class clazz = antTypeTable.getExposedClass(name);
  329. if (clazz == null) {
  330. continue;
  331. }
  332. if (Task.class.isAssignableFrom(clazz)) {
  333. taskClassDefinitions.put(
  334. name, antTypeTable.getTypeClass(name));
  335. }
  336. }
  337. rebuildTaskClassDefinitions = false;
  338. }
  339. }
  340. }
  341. return taskClassDefinitions;
  342. }
  343. /**
  344. * Returns the current type definition hashtable. The returned hashtable is
  345. * "live" and so should not be modified.
  346. *
  347. * @return a map of from type name to implementing class
  348. * (String to Class).
  349. */
  350. public Hashtable getDataTypeDefinitions() {
  351. synchronized (typeClassDefinitions) {
  352. synchronized (antTypeTable) {
  353. if (rebuildTypeClassDefinitions) {
  354. typeClassDefinitions.clear();
  355. for (Iterator i = antTypeTable.keySet().iterator();
  356. i.hasNext();) {
  357. String name = (String) i.next();
  358. Class clazz = antTypeTable.getExposedClass(name);
  359. if (clazz == null) {
  360. continue;
  361. }
  362. if (!(Task.class.isAssignableFrom(clazz))) {
  363. typeClassDefinitions.put(
  364. name, antTypeTable.getTypeClass(name));
  365. }
  366. }
  367. rebuildTypeClassDefinitions = false;
  368. }
  369. }
  370. }
  371. return typeClassDefinitions;
  372. }
  373. /**
  374. * Adds a new datatype definition.
  375. * Attempting to override an existing definition with an
  376. * equivalent one (i.e. with the same classname) results in
  377. * a verbose log message. Attempting to override an existing definition
  378. * with a different one results in a warning log message, but the
  379. * definition is changed.
  380. *
  381. * @param typeName The name of the datatype.
  382. * Must not be <code>null</code>.
  383. * @param typeClass The full name of the class implementing the datatype.
  384. * Must not be <code>null</code>.
  385. */
  386. public void addDataTypeDefinition(String typeName, Class typeClass) {
  387. AntTypeDefinition def = new AntTypeDefinition();
  388. def.setName(typeName);
  389. def.setClass(typeClass);
  390. updateDataTypeDefinition(def);
  391. project.log(" +User datatype: " + typeName + " "
  392. + typeClass.getName(), Project.MSG_DEBUG);
  393. }
  394. /**
  395. * Describe <code>addDataTypeDefinition</code> method here.
  396. *
  397. * @param def an <code>AntTypeDefinition</code> value.
  398. */
  399. public void addDataTypeDefinition(AntTypeDefinition def) {
  400. updateDataTypeDefinition(def);
  401. }
  402. /**
  403. * Returns the current datatype definition hashtable. The returned
  404. * hashtable is "live" and so should not be modified.
  405. *
  406. * @return a map of from datatype name to implementing class
  407. * (String to Class).
  408. */
  409. public Hashtable getAntTypeTable() {
  410. return antTypeTable;
  411. }
  412. /**
  413. * Creates a new instance of a task, adding it to a list of
  414. * created tasks for later invalidation. This causes all tasks
  415. * to be remembered until the containing project is removed
  416. *
  417. * Called from Project.createTask(), which can be called by tasks.
  418. * The method should be deprecated, as it doesn't support ns and libs.
  419. *
  420. * @param taskType The name of the task to create an instance of.
  421. * Must not be <code>null</code>.
  422. *
  423. * @return an instance of the specified task, or <code>null</code> if
  424. * the task name is not recognised.
  425. *
  426. * @exception BuildException if the task name is recognised but task
  427. * creation fails.
  428. */
  429. public Task createTask(String taskType) throws BuildException {
  430. Task task = createNewTask(taskType);
  431. if (task == null && taskType.equals(ANT_PROPERTY_TASK)) {
  432. // quick fix for Ant.java use of property before
  433. // initializing the project
  434. addTaskDefinition(ANT_PROPERTY_TASK,
  435. org.apache.tools.ant.taskdefs.Property.class);
  436. task = createNewTask(taskType);
  437. }
  438. if (task != null) {
  439. addCreatedTask(taskType, task);
  440. }
  441. return task;
  442. }
  443. /**
  444. * Creates a new instance of a task. This task is not
  445. * cached in the createdTasks list.
  446. * @since ant1.6
  447. * @param taskType The name of the task to create an instance of.
  448. * Must not be <code>null</code>.
  449. *
  450. * @return an instance of the specified task, or <code>null</code> if
  451. * the task name is not recognised.
  452. *
  453. * @exception BuildException if the task name is recognised but task
  454. * creation fails.
  455. */
  456. private Task createNewTask(String taskType) throws BuildException {
  457. Class c = getComponentClass(taskType);
  458. if (c == null || !(Task.class.isAssignableFrom(c))) {
  459. return null;
  460. }
  461. Object _task = createComponent(taskType);
  462. if (_task == null) {
  463. return null;
  464. }
  465. if (!(_task instanceof Task)) {
  466. throw new BuildException("Expected a Task from '" + taskType + "' but got an instance of " + _task.getClass().getName() + " instead");
  467. }
  468. Task task = (Task) _task;
  469. task.setTaskType(taskType);
  470. // set default value, can be changed by the user
  471. task.setTaskName(taskType);
  472. project.log(" +Task: " + taskType, Project.MSG_DEBUG);
  473. return task;
  474. }
  475. /**
  476. * Keeps a record of all tasks that have been created so that they
  477. * can be invalidated if a new task definition overrides the current one.
  478. *
  479. * @param type The name of the type of task which has been created.
  480. * Must not be <code>null</code>.
  481. *
  482. * @param task The freshly created task instance.
  483. * Must not be <code>null</code>.
  484. */
  485. private void addCreatedTask(String type, Task task) {
  486. synchronized (createdTasks) {
  487. Vector v = (Vector) createdTasks.get(type);
  488. if (v == null) {
  489. v = new Vector();
  490. createdTasks.put(type, v);
  491. }
  492. v.addElement(new WeakReference(task));
  493. }
  494. }
  495. /**
  496. * Mark tasks as invalid which no longer are of the correct type
  497. * for a given taskname.
  498. *
  499. * @param type The name of the type of task to invalidate.
  500. * Must not be <code>null</code>.
  501. */
  502. private void invalidateCreatedTasks(String type) {
  503. synchronized (createdTasks) {
  504. Vector v = (Vector) createdTasks.get(type);
  505. if (v != null) {
  506. Enumeration taskEnum = v.elements();
  507. while (taskEnum.hasMoreElements()) {
  508. WeakReference ref = (WeakReference) taskEnum.nextElement();
  509. Task t = (Task) ref.get();
  510. //being a weak ref, it may be null by this point
  511. if (t != null) {
  512. t.markInvalid();
  513. }
  514. }
  515. v.removeAllElements();
  516. createdTasks.remove(type);
  517. }
  518. }
  519. }
  520. /**
  521. * Creates a new instance of a data type.
  522. *
  523. * @param typeName The name of the data type to create an instance of.
  524. * Must not be <code>null</code>.
  525. *
  526. * @return an instance of the specified data type, or <code>null</code> if
  527. * the data type name is not recognised.
  528. *
  529. * @exception BuildException if the data type name is recognised but
  530. * instance creation fails.
  531. */
  532. public Object createDataType(String typeName) throws BuildException {
  533. return createComponent(typeName);
  534. }
  535. /**
  536. * Returns a description of the type of the given element.
  537. * <p>
  538. * This is useful for logging purposes.
  539. *
  540. * @param element The element to describe.
  541. * Must not be <code>null</code>.
  542. *
  543. * @return a description of the element type.
  544. *
  545. * @since Ant 1.6
  546. */
  547. public String getElementName(Object element) {
  548. return getElementName(element, false);
  549. }
  550. /**
  551. * Returns a description of the type of the given element.
  552. * <p>
  553. * This is useful for logging purposes.
  554. *
  555. * @param element The element to describe.
  556. * Must not be <code>null</code>.
  557. * @param brief whether to use a brief description.
  558. * @return a description of the element type.
  559. *
  560. * @since Ant 1.7
  561. */
  562. public String getElementName(Object element, boolean brief) {
  563. // PR: I do not know what to do if the object class
  564. // has multiple defines
  565. // but this is for logging only...
  566. String name = null;
  567. Class elementClass = element.getClass();
  568. for (Iterator i = antTypeTable.values().iterator(); i.hasNext();) {
  569. AntTypeDefinition def = (AntTypeDefinition) i.next();
  570. if (elementClass == def.getExposedClass(project)) {
  571. name = def.getName();
  572. return brief ? name : "The <" + name + "> type";
  573. }
  574. }
  575. name = elementClass.getName();
  576. return brief
  577. ? name.substring(name.lastIndexOf('.') + 1) : "Class " + name;
  578. }
  579. /**
  580. * Check if definition is a valid definition--it may be a
  581. * definition of an optional task that does not exist.
  582. * @param def the definition to test.
  583. * @return true if exposed type of definition is present.
  584. */
  585. private boolean validDefinition(AntTypeDefinition def) {
  586. return !(def.getTypeClass(project) == null
  587. || def.getExposedClass(project) == null);
  588. }
  589. /**
  590. * Check if two definitions are the same.
  591. * @param def the new definition.
  592. * @param old the old definition.
  593. * @return true if the two definitions are the same.
  594. */
  595. private boolean sameDefinition(
  596. AntTypeDefinition def, AntTypeDefinition old) {
  597. boolean defValid = validDefinition(def);
  598. boolean sameValidity = (defValid == validDefinition(old));
  599. //must have same validity; then if they are valid they must also be the same:
  600. return sameValidity && (!defValid || def.sameDefinition(old, project));
  601. }
  602. /**
  603. * Update the component definition table with a new or
  604. * modified definition.
  605. * @param def the definition to update or insert.
  606. */
  607. private void updateDataTypeDefinition(AntTypeDefinition def) {
  608. String name = def.getName();
  609. synchronized (antTypeTable) {
  610. rebuildTaskClassDefinitions = true;
  611. rebuildTypeClassDefinitions = true;
  612. AntTypeDefinition old = antTypeTable.getDefinition(name);
  613. if (old != null) {
  614. if (sameDefinition(def, old)) {
  615. return;
  616. }
  617. Class oldClass = antTypeTable.getExposedClass(name);
  618. boolean isTask =
  619. (oldClass != null && Task.class.isAssignableFrom(oldClass));
  620. project.log("Trying to override old definition of "
  621. + (isTask ? "task " : "datatype ") + name,
  622. (def.similarDefinition(old, project))
  623. ? Project.MSG_VERBOSE : Project.MSG_WARN);
  624. if (isTask) {
  625. invalidateCreatedTasks(name);
  626. }
  627. }
  628. project.log(" +Datatype " + name + " " + def.getClassName(),
  629. Project.MSG_DEBUG);
  630. antTypeTable.put(name, def);
  631. }
  632. }
  633. /**
  634. * Called at the start of processing an antlib.
  635. * @param uri the uri that is associated with this antlib.
  636. */
  637. public void enterAntLib(String uri) {
  638. antLibCurrentUri = uri;
  639. antLibStack.push(uri);
  640. }
  641. /**
  642. * @return the current antlib uri.
  643. */
  644. public String getCurrentAntlibUri() {
  645. return antLibCurrentUri;
  646. }
  647. /**
  648. * Called at the end of processing an antlib.
  649. */
  650. public void exitAntLib() {
  651. antLibStack.pop();
  652. antLibCurrentUri = (antLibStack.size() == 0)
  653. ? null : (String) antLibStack.peek();
  654. }
  655. /**
  656. * Load ant's tasks.
  657. */
  658. private void initTasks() {
  659. ClassLoader classLoader = null;
  660. classLoader = getClassLoader(classLoader);
  661. String dataDefs = MagicNames.TASKDEF_PROPERTIES_RESOURCE;
  662. InputStream in = null;
  663. try {
  664. Properties props = new Properties();
  665. in = this.getClass().getResourceAsStream(dataDefs);
  666. if (in == null) {
  667. throw new BuildException(ERROR_NO_TASK_LIST_LOAD);
  668. }
  669. props.load(in);
  670. Enumeration e = props.propertyNames();
  671. while (e.hasMoreElements()) {
  672. String name = (String) e.nextElement();
  673. String className = props.getProperty(name);
  674. AntTypeDefinition def = new AntTypeDefinition();
  675. def.setName(name);
  676. def.setClassName(className);
  677. def.setClassLoader(classLoader);
  678. def.setAdaptToClass(Task.class);
  679. def.setAdapterClass(TaskAdapter.class);
  680. antTypeTable.put(name, def);
  681. }
  682. } catch (IOException ex) {
  683. throw new BuildException(ERROR_NO_TASK_LIST_LOAD);
  684. } finally {
  685. if (in != null) {
  686. try {
  687. in.close();
  688. } catch (Exception ignore) {
  689. // Ignore
  690. }
  691. }
  692. }
  693. }
  694. private ClassLoader getClassLoader(ClassLoader classLoader) {
  695. String buildSysclasspath = project.getProperty(MagicNames.BUILD_SYSCLASSPATH);
  696. if (project.getCoreLoader() != null
  697. && !(BUILD_SYSCLASSPATH_ONLY.equals(buildSysclasspath))) {
  698. classLoader = project.getCoreLoader();
  699. }
  700. return classLoader;
  701. }
  702. /**
  703. * Load ant's datatypes.
  704. */
  705. private void initTypes() {
  706. ClassLoader classLoader = null;
  707. classLoader = getClassLoader(classLoader);
  708. String dataDefs = MagicNames.TYPEDEFS_PROPERTIES_RESOURCE;
  709. InputStream in = null;
  710. try {
  711. Properties props = new Properties();
  712. in = this.getClass().getResourceAsStream(dataDefs);
  713. if (in == null) {
  714. throw new BuildException(ERROR_NO_TYPE_LIST_LOAD);
  715. }
  716. props.load(in);
  717. Enumeration e = props.propertyNames();
  718. while (e.hasMoreElements()) {
  719. String name = (String) e.nextElement();
  720. String className = props.getProperty(name);
  721. AntTypeDefinition def = new AntTypeDefinition();
  722. def.setName(name);
  723. def.setClassName(className);
  724. def.setClassLoader(classLoader);
  725. antTypeTable.put(name, def);
  726. }
  727. } catch (IOException ex) {
  728. throw new BuildException(ERROR_NO_TYPE_LIST_LOAD);
  729. } finally {
  730. if (in != null) {
  731. try {
  732. in.close();
  733. } catch (Exception ignore) {
  734. // ignore
  735. }
  736. }
  737. }
  738. }
  739. /**
  740. * Called for each component name, check if the
  741. * associated URI has been examined for antlibs.
  742. */
  743. private synchronized void checkNamespace(String componentName) {
  744. String uri = ProjectHelper.extractUriFromComponentName(componentName);
  745. if ("".equals(uri)) {
  746. uri = ProjectHelper.ANT_CORE_URI;
  747. }
  748. if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) {
  749. return; // namespace that does not contain antlib
  750. }
  751. if (checkedNamespaces.contains(uri)) {
  752. return; // Already processed
  753. }
  754. checkedNamespaces.add(uri);
  755. Typedef definer = new Typedef();
  756. definer.setProject(project);
  757. definer.init();
  758. definer.setURI(uri);
  759. //there to stop error messages being "null"
  760. definer.setTaskName(uri);
  761. //if this is left out, bad things happen. like all build files break
  762. //on the first element encountered.
  763. definer.setResource(Definer.makeResourceFromURI(uri));
  764. // a fishing expedition :- ignore errors if antlib not present
  765. definer.setOnError(new Typedef.OnError(Typedef.OnError.POLICY_IGNORE));
  766. definer.execute();
  767. }
  768. /**
  769. * Handler called to do decent diagnosis on instantiation failure.
  770. * @param componentName component name.
  771. * @param type component type, used in error messages
  772. * @return a string containing as much diagnostics info as possible.
  773. */
  774. public String diagnoseCreationFailure(String componentName, String type) {
  775. StringWriter errorText = new StringWriter();
  776. PrintWriter out = new PrintWriter(errorText);
  777. out.println("Problem: failed to create " + type + " " + componentName);
  778. //class of problem
  779. boolean lowlevel = false;
  780. boolean jars = false;
  781. boolean definitions = false;
  782. boolean antTask;
  783. String home = System.getProperty(Launcher.USER_HOMEDIR);
  784. File libDir = new File(home, Launcher.USER_LIBDIR);
  785. //look up the name
  786. AntTypeDefinition def = getDefinition(componentName);
  787. if (def == null) {
  788. //not a known type
  789. boolean isAntlib = componentName.indexOf(MagicNames.ANTLIB_PREFIX) == 0;
  790. out.println("Cause: The name is undefined.");
  791. out.println("Action: Check the spelling.");
  792. out.println("Action: Check that any custom tasks/types have been declared.");
  793. out.println("Action: Check that any <presetdef>/<macrodef> declarations have taken place.");
  794. if (isAntlib) {
  795. out.println();
  796. out.println("This appears to be an antlib declaration. ");
  797. out.println("Action: Check that the implementing library exists "
  798. + "in ANT_HOME/lib or in ");
  799. out.println(" " + libDir);
  800. }
  801. definitions = true;
  802. } else {
  803. //we are defined, so it is an instantiation problem
  804. final String classname = def.getClassName();
  805. antTask = classname.startsWith("org.apache.tools.ant.");
  806. boolean optional = classname.startsWith("org.apache.tools.ant.taskdefs.optional");
  807. optional |= classname.startsWith("org.apache.tools.ant.types.optional");
  808. //start with instantiating the class.
  809. Class clazz = null;
  810. try {
  811. clazz = def.innerGetTypeClass();
  812. } catch (ClassNotFoundException e) {
  813. out.println("Cause: the class " + classname + " was not found.");
  814. jars = true;
  815. if (optional) {
  816. out.println(" This looks like one of Ant's optional components.");
  817. out.println("Action: Check that the appropriate optional JAR exists "
  818. + "in ANT_HOME/lib or in ");
  819. out.println(" " + libDir);
  820. } else {
  821. out.println("Action: Check that the component has been correctly declared");
  822. out.println(" and that the implementing JAR is in ANT_HOME/lib or in");
  823. out.println(" " + libDir);
  824. definitions = true;
  825. }
  826. } catch (NoClassDefFoundError ncdfe) {
  827. jars = true;
  828. out.println("Cause: Could not load a dependent class "
  829. + ncdfe.getMessage());
  830. if (optional) {
  831. out.println(" It is not enough to have Ant's optional JAR, you need the JAR");
  832. out.println(" files that it depends upon.");
  833. out.println("Ant's optional task dependencies are listed in the manual.");
  834. } else {
  835. out.println(" This class may be in a separate JAR that is not installed.");
  836. }
  837. out.println("Action: Determine what extra JAR files are needed, and place them");
  838. out.println(" in ANT_HOME/lib or");
  839. out.println(" in " + libDir);
  840. }
  841. //here we successfully loaded the class or failed.
  842. if (clazz != null) {
  843. //success: proceed with more steps
  844. try {
  845. def.innerCreateAndSet(clazz, project);
  846. //hey, there is nothing wrong with us
  847. out.println("The component could be instantiated.");
  848. } catch (NoSuchMethodException e) {
  849. lowlevel = true;
  850. out.println("Cause: The class " + classname
  851. + " has no compatible constructor.");
  852. } catch (InstantiationException e) {
  853. lowlevel = true;
  854. out.println("Cause: The class " + classname
  855. + " is abstract and cannot be instantiated.");
  856. } catch (IllegalAccessException e) {
  857. lowlevel = true;
  858. out.println("Cause: The constructor for " + classname
  859. + " is private and cannot be invoked.");
  860. } catch (InvocationTargetException ex) {
  861. lowlevel = true;
  862. Throwable t = ex.getTargetException();
  863. out.println("Cause: The constructor threw the exception");
  864. out.println(t.toString());
  865. t.printStackTrace(out);
  866. } catch (NoClassDefFoundError ncdfe) {
  867. jars = true;
  868. out.println("Cause: A class needed by class "
  869. + classname + " cannot be found: ");
  870. out.println(" " + ncdfe.getMessage());
  871. out.println("Action: Determine what extra JAR files are needed, and place them");
  872. out.println(" in ANT_HOME/lib or");
  873. out.println(" in " + libDir);
  874. }
  875. }
  876. out.println();
  877. out.println("Do not panic, this is a common problem.");
  878. if (definitions) {
  879. out.println("It may just be a typographical error in the build file "
  880. + "or the task/type declaration.");
  881. }
  882. if (jars) {
  883. out.println("The commonest cause is a missing JAR.");
  884. }
  885. if (lowlevel) {
  886. out.println("This is quite a low level problem, which may need "
  887. + "consultation with the author of the task.");
  888. if (antTask) {
  889. out.println("This may be the Ant team. Please file a "
  890. + "defect or contact the developer team.");
  891. } else {
  892. out.println("This does not appear to be a task bundled with Ant.");
  893. out.println("Please take it up with the supplier of the third-party "
  894. + type + ".");
  895. out.println("If you have written it yourself, you probably have a bug to fix.");
  896. }
  897. } else {
  898. out.println();
  899. out.println("This is not an bug; it is a configuration problem");
  900. }
  901. }
  902. out.flush();
  903. out.close();
  904. return errorText.toString();
  905. }
  906. /**
  907. * Map that contains the component definitions.
  908. */
  909. private static class AntTypeTable extends Hashtable {
  910. private Project project;
  911. AntTypeTable(Project project) {
  912. this.project = project;
  913. }
  914. AntTypeDefinition getDefinition(String key) {
  915. return (AntTypeDefinition) (super.get(key));
  916. }
  917. public Object get(Object key) {
  918. return getTypeClass((String) key);
  919. }
  920. Object create(String name) {
  921. AntTypeDefinition def = getDefinition(name);
  922. return (def == null) ? null : def.create(project);
  923. }
  924. Class getTypeClass(String name) {
  925. AntTypeDefinition def = getDefinition(name);
  926. return (def == null) ? null : def.getTypeClass(project);
  927. }
  928. Class getExposedClass(String name) {
  929. AntTypeDefinition def = getDefinition(name);
  930. return (def == null) ? null : def.getExposedClass(project);
  931. }
  932. public boolean contains(Object clazz) {
  933. boolean found = false;
  934. if (clazz instanceof Class) {
  935. for (Iterator i = values().iterator(); i.hasNext() && !found;) {
  936. found |= (((AntTypeDefinition) (i.next())).getExposedClass(
  937. project) == clazz);
  938. }
  939. }
  940. return found;
  941. }
  942. public boolean containsValue(Object value) {
  943. return contains(value);
  944. }
  945. }
  946. }