| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "Ant" and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.tools.ant; |
| |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.Stack; |
| |
| import java.util.Vector; |
| import java.io.InputStream; |
| import java.io.IOException; |
| import java.lang.ref.WeakReference; |
| import java.lang.reflect.Modifier; |
| |
| import org.apache.tools.ant.taskdefs.Typedef; |
| |
| /** |
| * Component creation and configuration. |
| * |
| * The class is based around handing component |
| * definitions in an AntTypeTable. |
| * |
| * The old task/type methods have been kept |
| * for backward compatibly. |
| * Project will just delegate its calls to this class. |
| * |
| * A very simple hook mechanism is provided that allows users to plug |
| * in custom code. It is also possible to replace the default behavior |
| * ( for example in an app embedding ant ) |
| * |
| * @author Costin Manolache |
| * @author Peter Reilly |
| * @author <a href="mailto:martijn@kruithof.xs4all.nl">Martijn Kruithof</a> |
| * @since Ant1.6 |
| */ |
| public class ComponentHelper { |
| /** Map from component name to anttypedefinition */ |
| private AntTypeTable antTypeTable; |
| |
| /** Map of tasks generated from antTypeTable */ |
| private Hashtable taskClassDefinitions = new Hashtable(); |
| /** flag to rebuild taskClassDefinitions */ |
| private boolean rebuildTaskClassDefinitions = true; |
| |
| /** Map of types generated from antTypeTable */ |
| private Hashtable typeClassDefinitions = new Hashtable(); |
| /** flag to rebuild typeClassDefinitions */ |
| private boolean rebuildTypeClassDefinitions = true; |
| |
| /** Set of namespaces that have been checked for antlibs */ |
| private Set checkedNamespaces = new HashSet(); |
| |
| /** |
| * Stack of antlib contexts used to resolve definitions while |
| * processing antlib |
| */ |
| private Stack antLibStack = new Stack(); |
| /** current antlib uri */ |
| private String antLibCurrentUri = null; |
| |
| /** |
| * Map from task names to vectors of created tasks |
| * (String to Vector of Task). This is used to invalidate tasks if |
| * the task definition changes. |
| */ |
| private Hashtable createdTasks = new Hashtable(); |
| |
| private ComponentHelper next; |
| private Project project; |
| |
| /** |
| * find a project component for a specific project, creating |
| * it if it does not exist |
| * @param project the project |
| * @return the project component for a specific project |
| */ |
| public static ComponentHelper getComponentHelper(Project project) { |
| // Singleton for now, it may change ( per/classloader ) |
| ComponentHelper ph = (ComponentHelper) project.getReference( |
| "ant.ComponentHelper"); |
| if (ph != null) { |
| return ph; |
| } |
| ph = new ComponentHelper(); |
| ph.setProject(project); |
| |
| project.addReference("ant.ComponentHelper", ph); |
| return ph; |
| } |
| |
| /** |
| * Creates a new ComponentHelper instance. |
| */ |
| protected ComponentHelper() { |
| } |
| |
| /** |
| * Set the next chained component helper |
| * |
| * @param next the next chained component helper |
| */ |
| public void setNext(ComponentHelper next) { |
| this.next = next; |
| } |
| |
| /** |
| * Get the next chained component helper |
| * |
| * @return the next chained component helper |
| */ |
| public ComponentHelper getNext() { |
| return next; |
| } |
| |
| /** |
| * Sets the project for this component helper |
| * |
| * @param project the project for this helper |
| */ |
| public void setProject(Project project) { |
| this.project = project; |
| antTypeTable = new AntTypeTable(project); |
| } |
| |
| /** |
| * Used with creating child projects. Each child |
| * project inherits the component definitions |
| * from its parent. |
| * @param helper the component helper of the parent project |
| */ |
| public void initSubProject(ComponentHelper helper) { |
| // add the types of the parent project |
| AntTypeTable typeTable = helper.antTypeTable; |
| for (Iterator i = typeTable.values().iterator(); i.hasNext();) { |
| AntTypeDefinition def = (AntTypeDefinition) i.next(); |
| antTypeTable.put(def.getName(), def); |
| } |
| // add the parsed namespaces of the parent project |
| checkedNamespaces.add(helper.checkedNamespaces); |
| } |
| |
| /** Factory method to create the components. |
| * |
| * This should be called by UnknownElement. |
| * |
| * @param ue The Unknown Element creating this component |
| * @param ns Namespace URI. Also available as ue.getNamespace() |
| * @param componentType The component type, |
| * Also available as ue.getComponentName() |
| * @return the created component |
| * @throws BuildException if an error occurs |
| */ |
| public Object createComponent(UnknownElement ue, |
| String ns, |
| String componentType) |
| throws BuildException { |
| Object component = createComponent(componentType); |
| if (component == null) { |
| return null; |
| } |
| |
| if (component instanceof Task) { |
| Task task = (Task) component; |
| task.setLocation(ue.getLocation()); |
| task.setTaskType(componentType); |
| task.setTaskName(ue.getTaskName()); |
| task.setOwningTarget(ue.getOwningTarget()); |
| task.init(); |
| addCreatedTask(componentType, task); |
| } |
| |
| return component; |
| } |
| |
| /** |
| * Create an object for a component. |
| * |
| * @param componentName the name of the component, if |
| * the component is in a namespace, the |
| * name is prefixed with the namespace uri and ":" |
| * @return the class if found or null if not. |
| */ |
| public Object createComponent(String componentName) { |
| AntTypeDefinition def = getDefinition(componentName); |
| if (def == null) { |
| return null; |
| } |
| return def.create(project); |
| } |
| |
| /** |
| * Return the class of the component name. |
| * |
| * @param componentName the name of the component, if |
| * the component is in a namespace, the |
| * name is prefixed with the namespace uri and ":" |
| * @return the class if found or null if not. |
| */ |
| public Class getComponentClass(String componentName) { |
| AntTypeDefinition def = getDefinition(componentName); |
| if (def == null) { |
| return null; |
| } |
| return def.getExposedClass(project); |
| } |
| |
| /** |
| * Return the antTypeDefinition for a componentName |
| * @param componentName the name of the component |
| * @return the ant definition or null if not present |
| */ |
| public AntTypeDefinition getDefinition(String componentName) { |
| checkNamespace(componentName); |
| AntTypeDefinition ret = null; |
| ret = antTypeTable.getDefinition(componentName); |
| return ret; |
| } |
| |
| /** |
| * Initialization code - implementing the original ant component |
| * loading from /org/apache/tools/ant/taskdefs/default.properties |
| * and .../types/default.properties |
| */ |
| public void initDefaultDefinitions() { |
| initTasks(); |
| initTypes(); |
| } |
| |
| /** |
| * Adds a new task definition to the project. |
| * Attempting to override an existing definition with an |
| * equivalent one (i.e. with the same classname) results in |
| * a verbose log message. Attempting to override an existing definition |
| * with a different one results in a warning log message and |
| * invalidates any tasks which have already been created with the |
| * old definition. |
| * |
| * @param taskName The name of the task to add. |
| * Must not be <code>null</code>. |
| * @param taskClass The full name of the class implementing the task. |
| * Must not be <code>null</code>. |
| * |
| * @exception BuildException if the class is unsuitable for being an Ant |
| * task. An error level message is logged before |
| * this exception is thrown. |
| * |
| * @see #checkTaskClass(Class) |
| */ |
| public void addTaskDefinition(String taskName, Class taskClass) { |
| checkTaskClass(taskClass); |
| AntTypeDefinition def = new AntTypeDefinition(); |
| def.setName(taskName); |
| def.setClassLoader(taskClass.getClassLoader()); |
| def.setClass(taskClass); |
| def.setAdapterClass(TaskAdapter.class); |
| def.setClassName(taskClass.getName()); |
| def.setAdaptToClass(Task.class); |
| updateDataTypeDefinition(def); |
| } |
| |
| /** |
| * Checks whether or not a class is suitable for serving as Ant task. |
| * Ant task implementation classes must be public, concrete, and have |
| * a no-arg constructor. |
| * |
| * @param taskClass The class to be checked. |
| * Must not be <code>null</code>. |
| * |
| * @exception BuildException if the class is unsuitable for being an Ant |
| * task. An error level message is logged before |
| * this exception is thrown. |
| */ |
| public void checkTaskClass(final Class taskClass) throws BuildException { |
| if (!Modifier.isPublic(taskClass.getModifiers())) { |
| final String message = taskClass + " is not public"; |
| project.log(message, Project.MSG_ERR); |
| throw new BuildException(message); |
| } |
| if (Modifier.isAbstract(taskClass.getModifiers())) { |
| final String message = taskClass + " is abstract"; |
| project.log(message, Project.MSG_ERR); |
| throw new BuildException(message); |
| } |
| try { |
| taskClass.getConstructor(null); |
| // don't have to check for public, since |
| // getConstructor finds public constructors only. |
| } catch (NoSuchMethodException e) { |
| final String message = "No public no-arg constructor in " |
| + taskClass; |
| project.log(message, Project.MSG_ERR); |
| throw new BuildException(message); |
| } |
| if (!Task.class.isAssignableFrom(taskClass)) { |
| TaskAdapter.checkTaskClass(taskClass, project); |
| } |
| } |
| |
| /** |
| * Returns the current task definition hashtable. The returned hashtable is |
| * "live" and so should not be modified. |
| * |
| * @return a map of from task name to implementing class |
| * (String to Class). |
| */ |
| public Hashtable getTaskDefinitions() { |
| synchronized (taskClassDefinitions) { |
| synchronized (antTypeTable) { |
| if (rebuildTaskClassDefinitions) { |
| taskClassDefinitions.clear(); |
| for (Iterator i = antTypeTable.keySet().iterator(); |
| i.hasNext();) { |
| String name = (String) i.next(); |
| Class clazz = |
| (Class) antTypeTable.getExposedClass(name); |
| if (clazz == null) { |
| continue; |
| } |
| if (Task.class.isAssignableFrom(clazz)) { |
| taskClassDefinitions.put( |
| name, antTypeTable.getTypeClass(name)); |
| } |
| } |
| rebuildTaskClassDefinitions = false; |
| } |
| } |
| } |
| return taskClassDefinitions; |
| } |
| |
| |
| /** |
| * Returns the current type definition hashtable. The returned hashtable is |
| * "live" and so should not be modified. |
| * |
| * @return a map of from type name to implementing class |
| * (String to Class). |
| */ |
| public Hashtable getDataTypeDefinitions() { |
| synchronized (typeClassDefinitions) { |
| synchronized (antTypeTable) { |
| if (rebuildTypeClassDefinitions) { |
| typeClassDefinitions.clear(); |
| for (Iterator i = antTypeTable.keySet().iterator(); |
| i.hasNext();) { |
| String name = (String) i.next(); |
| Class clazz = |
| (Class) antTypeTable.getExposedClass(name); |
| if (clazz == null) { |
| continue; |
| } |
| if (!(Task.class.isAssignableFrom(clazz))) { |
| typeClassDefinitions.put( |
| name, antTypeTable.getTypeClass(name)); |
| } |
| } |
| rebuildTypeClassDefinitions = false; |
| } |
| } |
| } |
| return typeClassDefinitions; |
| } |
| |
| /** |
| * Adds a new datatype definition. |
| * Attempting to override an existing definition with an |
| * equivalent one (i.e. with the same classname) results in |
| * a verbose log message. Attempting to override an existing definition |
| * with a different one results in a warning log message, but the |
| * definition is changed. |
| * |
| * @param typeName The name of the datatype. |
| * Must not be <code>null</code>. |
| * @param typeClass The full name of the class implementing the datatype. |
| * Must not be <code>null</code>. |
| */ |
| public void addDataTypeDefinition(String typeName, Class typeClass) { |
| AntTypeDefinition def = new AntTypeDefinition(); |
| def.setName(typeName); |
| def.setClass(typeClass); |
| updateDataTypeDefinition(def); |
| String msg = " +User datatype: " + typeName + " " |
| + typeClass.getName(); |
| project.log(msg, Project.MSG_DEBUG); |
| } |
| |
| /** |
| * Describe <code>addDataTypeDefinition</code> method here. |
| * |
| * @param def an <code>AntTypeDefinition</code> value |
| */ |
| public void addDataTypeDefinition(AntTypeDefinition def) { |
| updateDataTypeDefinition(def); |
| } |
| |
| /** |
| * Returns the current datatype definition hashtable. The returned |
| * hashtable is "live" and so should not be modified. |
| * |
| * @return a map of from datatype name to implementing class |
| * (String to Class). |
| */ |
| public Hashtable getAntTypeTable() { |
| return antTypeTable; |
| } |
| |
| /** |
| * Creates a new instance of a task, adding it to a list of |
| * created tasks for later invalidation. This causes all tasks |
| * to be remembered until the containing project is removed |
| * |
| * Called from Project.createTask(), which can be called by tasks. |
| * The method should be deprecated, as it doesn't support ns and libs. |
| * |
| * @param taskType The name of the task to create an instance of. |
| * Must not be <code>null</code>. |
| * |
| * @return an instance of the specified task, or <code>null</code> if |
| * the task name is not recognised. |
| * |
| * @exception BuildException if the task name is recognised but task |
| * creation fails. |
| */ |
| public Task createTask(String taskType) throws BuildException { |
| Task task = createNewTask(taskType); |
| if (task == null && taskType.equals("property")) { |
| // quick fix for Ant.java use of property before |
| // initializing the project |
| addTaskDefinition("property", |
| org.apache.tools.ant.taskdefs.Property.class); |
| task = createNewTask(taskType); |
| } |
| |
| if (task != null) { |
| addCreatedTask(taskType, task); |
| } |
| return task; |
| } |
| |
| /** |
| * Creates a new instance of a task. This task is not |
| * cached in the createdTasks list. |
| * @since ant1.6 |
| * @param taskType The name of the task to create an instance of. |
| * Must not be <code>null</code>. |
| * |
| * @return an instance of the specified task, or <code>null</code> if |
| * the task name is not recognised. |
| * |
| * @exception BuildException if the task name is recognised but task |
| * creation fails. |
| */ |
| private Task createNewTask(String taskType) throws BuildException { |
| Class c = getComponentClass(taskType); |
| if (c == null) { |
| return null; |
| } |
| |
| if (!(Task.class.isAssignableFrom(c))) { |
| return null; |
| } |
| Task task = (Task) createComponent(taskType); |
| if (task == null) { |
| return null; |
| } |
| task.setTaskType(taskType); |
| |
| // set default value, can be changed by the user |
| task.setTaskName(taskType); |
| |
| String msg = " +Task: " + taskType; |
| project.log (msg, Project.MSG_DEBUG); |
| return task; |
| } |
| |
| /** |
| * Keeps a record of all tasks that have been created so that they |
| * can be invalidated if a new task definition overrides the current one. |
| * |
| * @param type The name of the type of task which has been created. |
| * Must not be <code>null</code>. |
| * |
| * @param task The freshly created task instance. |
| * Must not be <code>null</code>. |
| */ |
| private void addCreatedTask(String type, Task task) { |
| synchronized (createdTasks) { |
| Vector v = (Vector) createdTasks.get(type); |
| if (v == null) { |
| v = new Vector(); |
| createdTasks.put(type, v); |
| } |
| v.addElement(new WeakReference(task)); |
| } |
| } |
| |
| /** |
| * Mark tasks as invalid which no longer are of the correct type |
| * for a given taskname. |
| * |
| * @param type The name of the type of task to invalidate. |
| * Must not be <code>null</code>. |
| */ |
| private void invalidateCreatedTasks(String type) { |
| synchronized (createdTasks) { |
| Vector v = (Vector) createdTasks.get(type); |
| if (v != null) { |
| Enumeration taskEnum = v.elements(); |
| while (taskEnum.hasMoreElements()) { |
| WeakReference ref = |
| (WeakReference) taskEnum.nextElement(); |
| Task t = (Task) ref.get(); |
| //being a weak ref, it may be null by this point |
| if (t != null) { |
| t.markInvalid(); |
| } |
| } |
| v.removeAllElements(); |
| createdTasks.remove(type); |
| } |
| } |
| } |
| |
| /** |
| * Creates a new instance of a data type. |
| * |
| * @param typeName The name of the data type to create an instance of. |
| * Must not be <code>null</code>. |
| * |
| * @return an instance of the specified data type, or <code>null</code> if |
| * the data type name is not recognised. |
| * |
| * @exception BuildException if the data type name is recognised but |
| * instance creation fails. |
| */ |
| public Object createDataType(String typeName) throws BuildException { |
| return createComponent(typeName); |
| } |
| |
| /** |
| * Returns a description of the type of the given element. |
| * <p> |
| * This is useful for logging purposes. |
| * |
| * @param element The element to describe. |
| * Must not be <code>null</code>. |
| * |
| * @return a description of the element type |
| * |
| * @since Ant 1.6 |
| */ |
| public String getElementName(Object element) { |
| // PR: I do not know what to do if the object class |
| // has multiple defines |
| // but this is for logging only... |
| Class elementClass = element.getClass(); |
| for (Iterator i = antTypeTable.values().iterator(); i.hasNext();) { |
| AntTypeDefinition def = (AntTypeDefinition) i.next(); |
| if (elementClass == def.getExposedClass(project)) { |
| return "The <" + def.getName() + "> type"; |
| } |
| } |
| return "Class " + elementClass.getName(); |
| } |
| |
| |
| /** |
| * check if definition is a valid definition - it |
| * may be a definition of an optional task that |
| * does not exist |
| * @param def the definition to test |
| * @return true if exposed type of definition is present |
| */ |
| private boolean validDefinition(AntTypeDefinition def) { |
| if (def.getTypeClass(project) == null |
| || def.getExposedClass(project) == null) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * check if two definitions are the same |
| * @param def the new definition |
| * @param old the old definition |
| * @return true if the two definitions are the same |
| */ |
| private boolean sameDefinition( |
| AntTypeDefinition def, AntTypeDefinition old) { |
| if (!validDefinition(def) || !validDefinition(old)) { |
| return validDefinition(def) == validDefinition(old); |
| } |
| return def.sameDefinition(old, project); |
| } |
| |
| |
| /** |
| * update the component definition table with a new or |
| * modified definition. |
| * @param def the definition to update or insert |
| */ |
| private void updateDataTypeDefinition(AntTypeDefinition def) { |
| String name = def.getName(); |
| synchronized (antTypeTable) { |
| rebuildTaskClassDefinitions = true; |
| rebuildTypeClassDefinitions = true; |
| AntTypeDefinition old = antTypeTable.getDefinition(name); |
| if (old != null) { |
| if (sameDefinition(def, old)) { |
| return; |
| } |
| int logLevel = Project.MSG_WARN; |
| if (def.similarDefinition(old, project)) { |
| logLevel = Project.MSG_VERBOSE; |
| } |
| Class oldClass = antTypeTable.getExposedClass(name); |
| boolean isTask = |
| (oldClass != null && Task.class.isAssignableFrom(oldClass)); |
| project.log( |
| "Trying to override old definition of " |
| + (isTask ? "task" : "datatype") |
| + " " + name, logLevel); |
| if (isTask) { |
| invalidateCreatedTasks(name); |
| } |
| } |
| project.log(" +Datatype " + name + " " + def.getClassName(), |
| Project.MSG_DEBUG); |
| antTypeTable.put(name, def); |
| } |
| } |
| |
| /** |
| * Called at the start of processing an antlib |
| * @param uri the uri that is associated with this antlib |
| */ |
| public void enterAntLib(String uri) { |
| antLibCurrentUri = uri; |
| antLibStack.push(uri); |
| } |
| |
| /** |
| * @return the current antlib uri |
| */ |
| public String getCurrentAntlibUri() { |
| return antLibCurrentUri; |
| } |
| |
| /** |
| * Called at the end of processing an antlib |
| */ |
| public void exitAntLib() { |
| antLibStack.pop(); |
| if (antLibStack.size() != 0) { |
| antLibCurrentUri = (String) antLibStack.peek(); |
| } else { |
| antLibCurrentUri = null; |
| } |
| } |
| |
| /** |
| * load ant's tasks |
| */ |
| private void initTasks() { |
| ClassLoader classLoader = null; |
| if (project.getCoreLoader() != null |
| && !("only".equals(project.getProperty("build.sysclasspath")))) { |
| classLoader = project.getCoreLoader(); |
| } |
| String dataDefs = "/org/apache/tools/ant/taskdefs/defaults.properties"; |
| |
| InputStream in = null; |
| try { |
| Properties props = new Properties(); |
| in = this.getClass().getResourceAsStream(dataDefs); |
| if (in == null) { |
| throw new BuildException("Can't load default task list"); |
| } |
| props.load(in); |
| |
| Enumeration e = props.propertyNames(); |
| while (e.hasMoreElements()) { |
| String name = (String) e.nextElement(); |
| String className = props.getProperty(name); |
| AntTypeDefinition def = new AntTypeDefinition(); |
| def.setName(name); |
| def.setClassName(className); |
| def.setClassLoader(classLoader); |
| def.setAdaptToClass(Task.class); |
| def.setAdapterClass(TaskAdapter.class); |
| antTypeTable.put(name, def); |
| } |
| } catch (IOException ex) { |
| throw new BuildException("Can't load default type list"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (Exception ignore) { |
| // Ignore |
| } |
| } |
| } |
| } |
| |
| /** |
| * load ant's datatypes |
| */ |
| private void initTypes() { |
| ClassLoader classLoader = null; |
| if (project.getCoreLoader() != null |
| && !("only".equals(project.getProperty("build.sysclasspath")))) { |
| classLoader = project.getCoreLoader(); |
| } |
| String dataDefs = "/org/apache/tools/ant/types/defaults.properties"; |
| |
| InputStream in = null; |
| try { |
| Properties props = new Properties(); |
| in = this.getClass().getResourceAsStream(dataDefs); |
| if (in == null) { |
| throw new BuildException("Can't load default datatype list"); |
| } |
| props.load(in); |
| |
| Enumeration e = props.propertyNames(); |
| while (e.hasMoreElements()) { |
| String name = (String) e.nextElement(); |
| String className = props.getProperty(name); |
| AntTypeDefinition def = new AntTypeDefinition(); |
| def.setName(name); |
| def.setClassName(className); |
| def.setClassLoader(classLoader); |
| antTypeTable.put(name, def); |
| } |
| } catch (IOException ex) { |
| throw new BuildException("Can't load default type list"); |
| } finally { |
| if (in != null) { |
| try { |
| in.close(); |
| } catch (Exception ignore) { |
| // ignore |
| } |
| } |
| } |
| } |
| |
| /** |
| * called for each component name, check if the |
| * associated URI has been examined for antlibs. |
| */ |
| private synchronized void checkNamespace(String componentName) { |
| if (componentName.indexOf(':') == -1) { |
| return; // not a namespaced name |
| } |
| |
| String uri = ProjectHelper.extractUriFromComponentName(componentName); |
| if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) { |
| return; // namespace that does not contain antlib |
| } |
| if (checkedNamespaces.contains(uri)) { |
| return; // Already processed |
| } |
| checkedNamespaces.add(uri); |
| Typedef definer = new Typedef(); |
| definer.setProject(project); |
| definer.setURI(uri); |
| definer.setResource( |
| uri.substring("antlib:".length()).replace('.', '/') |
| + "/antlib.xml"); |
| // a fishing expedition :- ignore errors if antlib not present |
| definer.setOnError(new Typedef.OnError("ignore")); |
| definer.init(); |
| definer.execute(); |
| } |
| |
| /** |
| * map that contains the component definitions |
| */ |
| private static class AntTypeTable extends Hashtable { |
| private Project project; |
| |
| public AntTypeTable(Project project) { |
| this.project = project; |
| } |
| |
| public AntTypeDefinition getDefinition(String key) { |
| AntTypeDefinition ret = (AntTypeDefinition) super.get(key); |
| return ret; |
| } |
| |
| /** Equivalent to getTypeType */ |
| public Object get(Object key) { |
| return getTypeClass((String) key); |
| } |
| |
| public Object create(String name) { |
| AntTypeDefinition def = getDefinition(name); |
| if (def == null) { |
| return null; |
| } |
| return def.create(project); |
| } |
| |
| public Class getTypeClass(String name) { |
| AntTypeDefinition def = getDefinition(name); |
| if (def == null) { |
| return null; |
| } |
| return def.getTypeClass(project); |
| } |
| |
| public Class getExposedClass(String name) { |
| AntTypeDefinition def = getDefinition(name); |
| if (def == null) { |
| return null; |
| } |
| return def.getExposedClass(project); |
| } |
| |
| public boolean contains(Object clazz) { |
| for (Iterator i = values().iterator(); i.hasNext();) { |
| AntTypeDefinition def = (AntTypeDefinition) i.next(); |
| Class c = def.getExposedClass(project); |
| if (c == clazz) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean containsValue(Object value) { |
| return contains(value); |
| } |
| } |
| |
| } |