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

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