1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import java.util.Enumeration;
  19. import java.util.Hashtable;
  20. import java.util.HashSet;
  21. import java.util.Iterator;
  22. import java.util.Properties;
  23. import java.util.Set;
  24. import java.util.Stack;
  25. import java.util.Vector;
  26. import java.io.InputStream;
  27. import java.io.IOException;
  28. import java.lang.ref.WeakReference;
  29. import java.lang.reflect.Modifier;
  30. import org.apache.tools.ant.taskdefs.Typedef;
  31. /**
  32. * Component creation and configuration.
  33. *
  34. * The class is based around handing component
  35. * definitions in an AntTypeTable.
  36. *
  37. * The old task/type methods have been kept
  38. * for backward compatibly.
  39. * Project will just delegate its calls to this class.
  40. *
  41. * A very simple hook mechanism is provided that allows users to plug
  42. * in custom code. It is also possible to replace the default behavior
  43. * ( for example in an app embedding ant )
  44. *
  45. * @since Ant1.6
  46. */
  47. public class ComponentHelper {
  48. /** Map from component name to anttypedefinition */
  49. private AntTypeTable antTypeTable;
  50. /** Map of tasks generated from antTypeTable */
  51. private Hashtable taskClassDefinitions = new Hashtable();
  52. /** flag to rebuild taskClassDefinitions */
  53. private boolean rebuildTaskClassDefinitions = true;
  54. /** Map of types generated from antTypeTable */
  55. private Hashtable typeClassDefinitions = new Hashtable();
  56. /** flag to rebuild typeClassDefinitions */
  57. private boolean rebuildTypeClassDefinitions = true;
  58. /** Set of namespaces that have been checked for antlibs */
  59. private Set checkedNamespaces = new HashSet();
  60. /**
  61. * Stack of antlib contexts used to resolve definitions while
  62. * processing antlib
  63. */
  64. private Stack antLibStack = new Stack();
  65. /** current antlib uri */
  66. private String antLibCurrentUri = null;
  67. /**
  68. * Map from task names to vectors of created tasks
  69. * (String to Vector of Task). This is used to invalidate tasks if
  70. * the task definition changes.
  71. */
  72. private Hashtable createdTasks = new Hashtable();
  73. private ComponentHelper next;
  74. private Project project;
  75. /**
  76. * find a project component for a specific project, creating
  77. * it if it does not exist
  78. * @param project the project
  79. * @return the project component for a specific project
  80. */
  81. public static ComponentHelper getComponentHelper(Project project) {
  82. // Singleton for now, it may change ( per/classloader )
  83. ComponentHelper ph = (ComponentHelper) project.getReference(
  84. "ant.ComponentHelper");
  85. if (ph != null) {
  86. return ph;
  87. }
  88. ph = new ComponentHelper();
  89. ph.setProject(project);
  90. project.addReference("ant.ComponentHelper", ph);
  91. return ph;
  92. }
  93. /**
  94. * Creates a new ComponentHelper instance.
  95. */
  96. protected ComponentHelper() {
  97. }
  98. /**
  99. * Set the next chained component helper
  100. *
  101. * @param next the next chained component helper
  102. */
  103. public void setNext(ComponentHelper next) {
  104. this.next = next;
  105. }
  106. /**
  107. * Get the next chained component helper
  108. *
  109. * @return the next chained component helper
  110. */
  111. public ComponentHelper getNext() {
  112. return next;
  113. }
  114. /**
  115. * Sets the project for this component helper
  116. *
  117. * @param project the project for this helper
  118. */
  119. public void setProject(Project project) {
  120. this.project = project;
  121. antTypeTable = new AntTypeTable(project);
  122. }
  123. /**
  124. * Used with creating child projects. Each child
  125. * project inherits the component definitions
  126. * from its parent.
  127. * @param helper the component helper of the parent project
  128. */
  129. public void initSubProject(ComponentHelper helper) {
  130. // add the types of the parent project
  131. AntTypeTable typeTable = helper.antTypeTable;
  132. for (Iterator i = typeTable.values().iterator(); i.hasNext();) {
  133. AntTypeDefinition def = (AntTypeDefinition) i.next();
  134. antTypeTable.put(def.getName(), def);
  135. }
  136. // add the parsed namespaces of the parent project
  137. for (Iterator i = helper.checkedNamespaces.iterator(); i.hasNext();) {
  138. checkedNamespaces.add(i.next());
  139. }
  140. }
  141. /** Factory method to create the components.
  142. *
  143. * This should be called by UnknownElement.
  144. *
  145. * @param ue The Unknown Element creating this component
  146. * @param ns Namespace URI. Also available as ue.getNamespace()
  147. * @param componentType The component type,
  148. * Also available as ue.getComponentName()
  149. * @return the created component
  150. * @throws BuildException if an error occurs
  151. */
  152. public Object createComponent(UnknownElement ue,
  153. String ns,
  154. String componentType)
  155. throws BuildException {
  156. Object component = createComponent(componentType);
  157. if (component == null) {
  158. return null;
  159. }
  160. if (component instanceof Task) {
  161. Task task = (Task) component;
  162. task.setLocation(ue.getLocation());
  163. task.setTaskType(componentType);
  164. task.setTaskName(ue.getTaskName());
  165. task.setOwningTarget(ue.getOwningTarget());
  166. task.init();
  167. addCreatedTask(componentType, task);
  168. }
  169. return component;
  170. }
  171. /**
  172. * Create an object for a component.
  173. *
  174. * @param componentName the name of the component, if
  175. * the component is in a namespace, the
  176. * name is prefixed with the namespace uri and ":"
  177. * @return the class if found or null if not.
  178. */
  179. public Object createComponent(String componentName) {
  180. AntTypeDefinition def = getDefinition(componentName);
  181. if (def == null) {
  182. return null;
  183. }
  184. return def.create(project);
  185. }
  186. /**
  187. * Return the class of the component name.
  188. *
  189. * @param componentName the name of the component, if
  190. * the component is in a namespace, the
  191. * name is prefixed with the namespace uri and ":"
  192. * @return the class if found or null if not.
  193. */
  194. public Class getComponentClass(String componentName) {
  195. AntTypeDefinition def = getDefinition(componentName);
  196. if (def == null) {
  197. return null;
  198. }
  199. return def.getExposedClass(project);
  200. }
  201. /**
  202. * Return the antTypeDefinition for a componentName
  203. * @param componentName the name of the component
  204. * @return the ant definition or null if not present
  205. */
  206. public AntTypeDefinition getDefinition(String componentName) {
  207. checkNamespace(componentName);
  208. AntTypeDefinition ret = null;
  209. ret = antTypeTable.getDefinition(componentName);
  210. return ret;
  211. }
  212. /**
  213. * This method is initialization code implementing the original ant component
  214. * loading from /org/apache/tools/ant/taskdefs/default.properties
  215. * and /org/apache/tools/ant/types/default.properties.
  216. */
  217. public void initDefaultDefinitions() {
  218. initTasks();
  219. initTypes();
  220. }
  221. /**
  222. * Adds a new task definition to the project.
  223. * Attempting to override an existing definition with an
  224. * equivalent one (i.e. with the same classname) results in
  225. * a verbose log message. Attempting to override an existing definition
  226. * with a different one results in a warning log message and
  227. * invalidates any tasks which have already been created with the
  228. * old definition.
  229. *
  230. * @param taskName The name of the task to add.
  231. * Must not be <code>null</code>.
  232. * @param taskClass The full name of the class implementing the task.
  233. * Must not be <code>null</code>.
  234. *
  235. * @exception BuildException if the class is unsuitable for being an Ant
  236. * task. An error level message is logged before
  237. * this exception is thrown.
  238. *
  239. * @see #checkTaskClass(Class)
  240. */
  241. public void addTaskDefinition(String taskName, Class taskClass) {
  242. checkTaskClass(taskClass);
  243. AntTypeDefinition def = new AntTypeDefinition();
  244. def.setName(taskName);
  245. def.setClassLoader(taskClass.getClassLoader());
  246. def.setClass(taskClass);
  247. def.setAdapterClass(TaskAdapter.class);
  248. def.setClassName(taskClass.getName());
  249. def.setAdaptToClass(Task.class);
  250. updateDataTypeDefinition(def);
  251. }
  252. /**
  253. * Checks whether or not a class is suitable for serving as Ant task.
  254. * Ant task implementation classes must be public, concrete, and have
  255. * a no-arg constructor.
  256. *
  257. * @param taskClass The class to be checked.
  258. * Must not be <code>null</code>.
  259. *
  260. * @exception BuildException if the class is unsuitable for being an Ant
  261. * task. An error level message is logged before
  262. * this exception is thrown.
  263. */
  264. public void checkTaskClass(final Class taskClass) throws BuildException {
  265. if (!Modifier.isPublic(taskClass.getModifiers())) {
  266. final String message = taskClass + " is not public";
  267. project.log(message, Project.MSG_ERR);
  268. throw new BuildException(message);
  269. }
  270. if (Modifier.isAbstract(taskClass.getModifiers())) {
  271. final String message = taskClass + " is abstract";
  272. project.log(message, Project.MSG_ERR);
  273. throw new BuildException(message);
  274. }
  275. try {
  276. taskClass.getConstructor(null);
  277. // don't have to check for public, since
  278. // getConstructor finds public constructors only.
  279. } catch (NoSuchMethodException e) {
  280. final String message = "No public no-arg constructor in "
  281. + taskClass;
  282. project.log(message, Project.MSG_ERR);
  283. throw new BuildException(message);
  284. }
  285. if (!Task.class.isAssignableFrom(taskClass)) {
  286. TaskAdapter.checkTaskClass(taskClass, project);
  287. }
  288. }
  289. /**
  290. * Returns the current task definition hashtable. The returned hashtable is
  291. * "live" and so should not be modified.
  292. *
  293. * @return a map of from task name to implementing class
  294. * (String to Class).
  295. */
  296. public Hashtable getTaskDefinitions() {
  297. synchronized (taskClassDefinitions) {
  298. synchronized (antTypeTable) {
  299. if (rebuildTaskClassDefinitions) {
  300. taskClassDefinitions.clear();
  301. for (Iterator i = antTypeTable.keySet().iterator();
  302. i.hasNext();) {
  303. String name = (String) i.next();
  304. Class clazz =
  305. (Class) antTypeTable.getExposedClass(name);
  306. if (clazz == null) {
  307. continue;
  308. }
  309. if (Task.class.isAssignableFrom(clazz)) {
  310. taskClassDefinitions.put(
  311. name, antTypeTable.getTypeClass(name));
  312. }
  313. }
  314. rebuildTaskClassDefinitions = false;
  315. }
  316. }
  317. }
  318. return taskClassDefinitions;
  319. }
  320. /**
  321. * Returns the current type definition hashtable. The returned hashtable is
  322. * "live" and so should not be modified.
  323. *
  324. * @return a map of from type name to implementing class
  325. * (String to Class).
  326. */
  327. public Hashtable getDataTypeDefinitions() {
  328. synchronized (typeClassDefinitions) {
  329. synchronized (antTypeTable) {
  330. if (rebuildTypeClassDefinitions) {
  331. typeClassDefinitions.clear();
  332. for (Iterator i = antTypeTable.keySet().iterator();
  333. i.hasNext();) {
  334. String name = (String) i.next();
  335. Class clazz =
  336. (Class) antTypeTable.getExposedClass(name);
  337. if (clazz == null) {
  338. continue;
  339. }
  340. if (!(Task.class.isAssignableFrom(clazz))) {
  341. typeClassDefinitions.put(
  342. name, antTypeTable.getTypeClass(name));
  343. }
  344. }
  345. rebuildTypeClassDefinitions = false;
  346. }
  347. }
  348. }
  349. return typeClassDefinitions;
  350. }
  351. /**
  352. * Adds a new datatype definition.
  353. * Attempting to override an existing definition with an
  354. * equivalent one (i.e. with the same classname) results in
  355. * a verbose log message. Attempting to override an existing definition
  356. * with a different one results in a warning log message, but the
  357. * definition is changed.
  358. *
  359. * @param typeName The name of the datatype.
  360. * Must not be <code>null</code>.
  361. * @param typeClass The full name of the class implementing the datatype.
  362. * Must not be <code>null</code>.
  363. */
  364. public void addDataTypeDefinition(String typeName, Class typeClass) {
  365. AntTypeDefinition def = new AntTypeDefinition();
  366. def.setName(typeName);
  367. def.setClass(typeClass);
  368. updateDataTypeDefinition(def);
  369. String msg = " +User datatype: " + typeName + " "
  370. + typeClass.getName();
  371. project.log(msg, Project.MSG_DEBUG);
  372. }
  373. /**
  374. * Describe <code>addDataTypeDefinition</code> method here.
  375. *
  376. * @param def an <code>AntTypeDefinition</code> value
  377. */
  378. public void addDataTypeDefinition(AntTypeDefinition def) {
  379. updateDataTypeDefinition(def);
  380. }
  381. /**
  382. * Returns the current datatype definition hashtable. The returned
  383. * hashtable is "live" and so should not be modified.
  384. *
  385. * @return a map of from datatype name to implementing class
  386. * (String to Class).
  387. */
  388. public Hashtable getAntTypeTable() {
  389. return antTypeTable;
  390. }
  391. /**
  392. * Creates a new instance of a task, adding it to a list of
  393. * created tasks for later invalidation. This causes all tasks
  394. * to be remembered until the containing project is removed
  395. *
  396. * Called from Project.createTask(), which can be called by tasks.
  397. * The method should be deprecated, as it doesn't support ns and libs.
  398. *
  399. * @param taskType The name of the task to create an instance of.
  400. * Must not be <code>null</code>.
  401. *
  402. * @return an instance of the specified task, or <code>null</code> if
  403. * the task name is not recognised.
  404. *
  405. * @exception BuildException if the task name is recognised but task
  406. * creation fails.
  407. */
  408. public Task createTask(String taskType) throws BuildException {
  409. Task task = createNewTask(taskType);
  410. if (task == null && taskType.equals("property")) {
  411. // quick fix for Ant.java use of property before
  412. // initializing the project
  413. addTaskDefinition("property",
  414. org.apache.tools.ant.taskdefs.Property.class);
  415. task = createNewTask(taskType);
  416. }
  417. if (task != null) {
  418. addCreatedTask(taskType, task);
  419. }
  420. return task;
  421. }
  422. /**
  423. * Creates a new instance of a task. This task is not
  424. * cached in the createdTasks list.
  425. * @since ant1.6
  426. * @param taskType The name of the task to create an instance of.
  427. * Must not be <code>null</code>.
  428. *
  429. * @return an instance of the specified task, or <code>null</code> if
  430. * the task name is not recognised.
  431. *
  432. * @exception BuildException if the task name is recognised but task
  433. * creation fails.
  434. */
  435. private Task createNewTask(String taskType) throws BuildException {
  436. Class c = getComponentClass(taskType);
  437. if (c == null) {
  438. return null;
  439. }
  440. if (!(Task.class.isAssignableFrom(c))) {
  441. return null;
  442. }
  443. Task task = (Task) createComponent(taskType);
  444. if (task == null) {
  445. return null;
  446. }
  447. task.setTaskType(taskType);
  448. // set default value, can be changed by the user
  449. task.setTaskName(taskType);
  450. String msg = " +Task: " + taskType;
  451. project.log (msg, Project.MSG_DEBUG);
  452. return task;
  453. }
  454. /**
  455. * Keeps a record of all tasks that have been created so that they
  456. * can be invalidated if a new task definition overrides the current one.
  457. *
  458. * @param type The name of the type of task which has been created.
  459. * Must not be <code>null</code>.
  460. *
  461. * @param task The freshly created task instance.
  462. * Must not be <code>null</code>.
  463. */
  464. private void addCreatedTask(String type, Task task) {
  465. synchronized (createdTasks) {
  466. Vector v = (Vector) createdTasks.get(type);
  467. if (v == null) {
  468. v = new Vector();
  469. createdTasks.put(type, v);
  470. }
  471. v.addElement(new WeakReference(task));
  472. }
  473. }
  474. /**
  475. * Mark tasks as invalid which no longer are of the correct type
  476. * for a given taskname.
  477. *
  478. * @param type The name of the type of task to invalidate.
  479. * Must not be <code>null</code>.
  480. */
  481. private void invalidateCreatedTasks(String type) {
  482. synchronized (createdTasks) {
  483. Vector v = (Vector) createdTasks.get(type);
  484. if (v != null) {
  485. Enumeration taskEnum = v.elements();
  486. while (taskEnum.hasMoreElements()) {
  487. WeakReference ref =
  488. (WeakReference) taskEnum.nextElement();
  489. Task t = (Task) ref.get();
  490. //being a weak ref, it may be null by this point
  491. if (t != null) {
  492. t.markInvalid();
  493. }
  494. }
  495. v.removeAllElements();
  496. createdTasks.remove(type);
  497. }
  498. }
  499. }
  500. /**
  501. * Creates a new instance of a data type.
  502. *
  503. * @param typeName The name of the data type to create an instance of.
  504. * Must not be <code>null</code>.
  505. *
  506. * @return an instance of the specified data type, or <code>null</code> if
  507. * the data type name is not recognised.
  508. *
  509. * @exception BuildException if the data type name is recognised but
  510. * instance creation fails.
  511. */
  512. public Object createDataType(String typeName) throws BuildException {
  513. return createComponent(typeName);
  514. }
  515. /**
  516. * Returns a description of the type of the given element.
  517. * <p>
  518. * This is useful for logging purposes.
  519. *
  520. * @param element The element to describe.
  521. * Must not be <code>null</code>.
  522. *
  523. * @return a description of the element type
  524. *
  525. * @since Ant 1.6
  526. */
  527. public String getElementName(Object element) {
  528. // PR: I do not know what to do if the object class
  529. // has multiple defines
  530. // but this is for logging only...
  531. Class elementClass = element.getClass();
  532. for (Iterator i = antTypeTable.values().iterator(); i.hasNext();) {
  533. AntTypeDefinition def = (AntTypeDefinition) i.next();
  534. if (elementClass == def.getExposedClass(project)) {
  535. return "The <" + def.getName() + "> type";
  536. }
  537. }
  538. return "Class " + elementClass.getName();
  539. }
  540. /**
  541. * check if definition is a valid definition - it
  542. * may be a definition of an optional task that
  543. * does not exist
  544. * @param def the definition to test
  545. * @return true if exposed type of definition is present
  546. */
  547. private boolean validDefinition(AntTypeDefinition def) {
  548. if (def.getTypeClass(project) == null
  549. || def.getExposedClass(project) == null) {
  550. return false;
  551. }
  552. return true;
  553. }
  554. /**
  555. * check if two definitions are the same
  556. * @param def the new definition
  557. * @param old the old definition
  558. * @return true if the two definitions are the same
  559. */
  560. private boolean sameDefinition(
  561. AntTypeDefinition def, AntTypeDefinition old) {
  562. if (!validDefinition(def) || !validDefinition(old)) {
  563. return validDefinition(def) == validDefinition(old);
  564. }
  565. return def.sameDefinition(old, project);
  566. }
  567. /**
  568. * update the component definition table with a new or
  569. * modified definition.
  570. * @param def the definition to update or insert
  571. */
  572. private void updateDataTypeDefinition(AntTypeDefinition def) {
  573. String name = def.getName();
  574. synchronized (antTypeTable) {
  575. rebuildTaskClassDefinitions = true;
  576. rebuildTypeClassDefinitions = true;
  577. AntTypeDefinition old = antTypeTable.getDefinition(name);
  578. if (old != null) {
  579. if (sameDefinition(def, old)) {
  580. return;
  581. }
  582. int logLevel = Project.MSG_WARN;
  583. if (def.similarDefinition(old, project)) {
  584. logLevel = Project.MSG_VERBOSE;
  585. }
  586. Class oldClass = antTypeTable.getExposedClass(name);
  587. boolean isTask =
  588. (oldClass != null && Task.class.isAssignableFrom(oldClass));
  589. project.log(
  590. "Trying to override old definition of "
  591. + (isTask ? "task" : "datatype")
  592. + " " + name, logLevel);
  593. if (isTask) {
  594. invalidateCreatedTasks(name);
  595. }
  596. }
  597. project.log(" +Datatype " + name + " " + def.getClassName(),
  598. Project.MSG_DEBUG);
  599. antTypeTable.put(name, def);
  600. }
  601. }
  602. /**
  603. * Called at the start of processing an antlib
  604. * @param uri the uri that is associated with this antlib
  605. */
  606. public void enterAntLib(String uri) {
  607. antLibCurrentUri = uri;
  608. antLibStack.push(uri);
  609. }
  610. /**
  611. * @return the current antlib uri
  612. */
  613. public String getCurrentAntlibUri() {
  614. return antLibCurrentUri;
  615. }
  616. /**
  617. * Called at the end of processing an antlib
  618. */
  619. public void exitAntLib() {
  620. antLibStack.pop();
  621. if (antLibStack.size() != 0) {
  622. antLibCurrentUri = (String) antLibStack.peek();
  623. } else {
  624. antLibCurrentUri = null;
  625. }
  626. }
  627. /**
  628. * load ant's tasks
  629. */
  630. private void initTasks() {
  631. ClassLoader classLoader = null;
  632. if (project.getCoreLoader() != null
  633. && !("only".equals(project.getProperty("build.sysclasspath")))) {
  634. classLoader = project.getCoreLoader();
  635. }
  636. String dataDefs = "/org/apache/tools/ant/taskdefs/defaults.properties";
  637. InputStream in = null;
  638. try {
  639. Properties props = new Properties();
  640. in = this.getClass().getResourceAsStream(dataDefs);
  641. if (in == null) {
  642. throw new BuildException("Can't load default task list");
  643. }
  644. props.load(in);
  645. Enumeration e = props.propertyNames();
  646. while (e.hasMoreElements()) {
  647. String name = (String) e.nextElement();
  648. String className = props.getProperty(name);
  649. AntTypeDefinition def = new AntTypeDefinition();
  650. def.setName(name);
  651. def.setClassName(className);
  652. def.setClassLoader(classLoader);
  653. def.setAdaptToClass(Task.class);
  654. def.setAdapterClass(TaskAdapter.class);
  655. antTypeTable.put(name, def);
  656. }
  657. } catch (IOException ex) {
  658. throw new BuildException("Can't load default type list");
  659. } finally {
  660. if (in != null) {
  661. try {
  662. in.close();
  663. } catch (Exception ignore) {
  664. // Ignore
  665. }
  666. }
  667. }
  668. }
  669. /**
  670. * load ant's datatypes
  671. */
  672. private void initTypes() {
  673. ClassLoader classLoader = null;
  674. if (project.getCoreLoader() != null
  675. && !("only".equals(project.getProperty("build.sysclasspath")))) {
  676. classLoader = project.getCoreLoader();
  677. }
  678. String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
  679. InputStream in = null;
  680. try {
  681. Properties props = new Properties();
  682. in = this.getClass().getResourceAsStream(dataDefs);
  683. if (in == null) {
  684. throw new BuildException("Can't load default datatype list");
  685. }
  686. props.load(in);
  687. Enumeration e = props.propertyNames();
  688. while (e.hasMoreElements()) {
  689. String name = (String) e.nextElement();
  690. String className = props.getProperty(name);
  691. AntTypeDefinition def = new AntTypeDefinition();
  692. def.setName(name);
  693. def.setClassName(className);
  694. def.setClassLoader(classLoader);
  695. antTypeTable.put(name, def);
  696. }
  697. } catch (IOException ex) {
  698. throw new BuildException("Can't load default type list");
  699. } finally {
  700. if (in != null) {
  701. try {
  702. in.close();
  703. } catch (Exception ignore) {
  704. // ignore
  705. }
  706. }
  707. }
  708. }
  709. /**
  710. * called for each component name, check if the
  711. * associated URI has been examined for antlibs.
  712. */
  713. private synchronized void checkNamespace(String componentName) {
  714. if (componentName.indexOf(':') == -1) {
  715. return; // not a namespaced name
  716. }
  717. String uri = ProjectHelper.extractUriFromComponentName(componentName);
  718. if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) {
  719. return; // namespace that does not contain antlib
  720. }
  721. if (checkedNamespaces.contains(uri)) {
  722. return; // Already processed
  723. }
  724. checkedNamespaces.add(uri);
  725. Typedef definer = new Typedef();
  726. definer.setProject(project);
  727. definer.setURI(uri);
  728. definer.setResource(
  729. uri.substring("antlib:".length()).replace('.', '/')
  730. + "/antlib.xml");
  731. // a fishing expedition :- ignore errors if antlib not present
  732. definer.setOnError(new Typedef.OnError("ignore"));
  733. definer.init();
  734. definer.execute();
  735. }
  736. /**
  737. * map that contains the component definitions
  738. */
  739. private static class AntTypeTable extends Hashtable {
  740. private Project project;
  741. public AntTypeTable(Project project) {
  742. this.project = project;
  743. }
  744. public AntTypeDefinition getDefinition(String key) {
  745. AntTypeDefinition ret = (AntTypeDefinition) super.get(key);
  746. return ret;
  747. }
  748. /** Equivalent to getTypeType */
  749. public Object get(Object key) {
  750. return getTypeClass((String) key);
  751. }
  752. public Object create(String name) {
  753. AntTypeDefinition def = getDefinition(name);
  754. if (def == null) {
  755. return null;
  756. }
  757. return def.create(project);
  758. }
  759. public Class getTypeClass(String name) {
  760. AntTypeDefinition def = getDefinition(name);
  761. if (def == null) {
  762. return null;
  763. }
  764. return def.getTypeClass(project);
  765. }
  766. public Class getExposedClass(String name) {
  767. AntTypeDefinition def = getDefinition(name);
  768. if (def == null) {
  769. return null;
  770. }
  771. return def.getExposedClass(project);
  772. }
  773. public boolean contains(Object clazz) {
  774. for (Iterator i = values().iterator(); i.hasNext();) {
  775. AntTypeDefinition def = (AntTypeDefinition) i.next();
  776. Class c = def.getExposedClass(project);
  777. if (c == clazz) {
  778. return true;
  779. }
  780. }
  781. return false;
  782. }
  783. public boolean containsValue(Object value) {
  784. return contains(value);
  785. }
  786. }
  787. }