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