diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/ComponentHelper.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/ComponentHelper.java | 1101 |
1 files changed, 0 insertions, 1101 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/ComponentHelper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/ComponentHelper.java deleted file mode 100644 index eceedeef..00000000 --- a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/ComponentHelper.java +++ /dev/null @@ -1,1101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.tools.ant; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.Stack; - -import org.apache.tools.ant.launch.Launcher; -import org.apache.tools.ant.taskdefs.Definer; -import org.apache.tools.ant.taskdefs.Typedef; -import org.apache.tools.ant.util.FileUtils; - -/** - * 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 ) - * - * @since Ant1.6 - */ -public class ComponentHelper { - /** Map of component name to lists of restricted definitions */ - private Map<String, List<AntTypeDefinition>> restrictedDefinitions = new HashMap<String, List<AntTypeDefinition>>(); - - /** Map from component name to anttypedefinition */ - private final Hashtable<String, AntTypeDefinition> antTypeTable = new Hashtable<String, AntTypeDefinition>(); - - /** Map of tasks generated from antTypeTable */ - private final Hashtable<String, Class<?>> taskClassDefinitions = new Hashtable<String, Class<?>>(); - - /** flag to rebuild taskClassDefinitions */ - private boolean rebuildTaskClassDefinitions = true; - - /** Map of types generated from antTypeTable */ - private final Hashtable<String, Class<?>> typeClassDefinitions = new Hashtable<String, Class<?>>(); - - /** flag to rebuild typeClassDefinitions */ - private boolean rebuildTypeClassDefinitions = true; - - /** Set of namespaces that have been checked for antlibs */ - private final HashSet<String> checkedNamespaces = new HashSet<String>(); - - /** - * Stack of antlib contexts used to resolve definitions while - * processing antlib - */ - private Stack<String> antLibStack = new Stack<String>(); - - /** current antlib uri */ - private String antLibCurrentUri = null; - - /** - * this does not appear to be used anywhere in the Ant codebase - * even via its accessors - */ - private ComponentHelper next; - - /** - * Project that owns a component helper - */ - private Project project; - - /** - * Error string when the file taskdefs/defaults.properties cannot be found - */ - private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load default task list"; - - /** - * Error string when the typedefs/defaults.properties cannot be found - */ - private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list"; - - /** - * reference under which we register ourselves with a project -{@value} - */ - public static final String COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper"; - - /** - * string used to control build.syspath policy {@value} - */ - private static final String BUILD_SYSCLASSPATH_ONLY = "only"; - - /** - * special name of ant's property task -{@value}. There is some - * contrived work here to enable this early. - */ - private static final String ANT_PROPERTY_TASK = "property"; - - // {tasks, types} - private static Properties[] defaultDefinitions = new Properties[2]; - - /** - * Get the project. - * @return the project owner of this helper. - */ - public Project getProject() { - return 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) { - if (project == null) { - return null; - } - // Singleton for now, it may change ( per/classloader ) - ComponentHelper ph = (ComponentHelper) project.getReference(COMPONENT_HELPER_REFERENCE); - if (ph != null) { - return ph; - } - ph = new ComponentHelper(); - ph.setProject(project); - - project.addReference(COMPONENT_HELPER_REFERENCE, 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 Hashtable<String, AntTypeDefinition>(project); - } - - /** - * @return A copy of the CheckedNamespace. - */ - private synchronized Set<String> getCheckedNamespace() { - @SuppressWarnings("unchecked") - final Set<String> result = (Set<String>) checkedNamespaces.clone(); - return result; - } - - /** - * @return A deep copy of the restrictredDefinition - */ - private Map<String, List<AntTypeDefinition>> getRestrictedDefinition() { - final Map<String, List<AntTypeDefinition>> result = new HashMap<String, List<AntTypeDefinition>>(); - synchronized (restrictedDefinitions) { - for (Map.Entry<String, List<AntTypeDefinition>> entry : restrictedDefinitions.entrySet()) { - List<AntTypeDefinition> entryVal = entry.getValue(); - synchronized (entryVal) { - //copy the entryVal - entryVal = new ArrayList<AntTypeDefinition> (entryVal); - } - result.put(entry.getKey(), entryVal); - } - } - return result; - } - - - /** - * 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 - @SuppressWarnings("unchecked") - final Hashtable<String, AntTypeDefinition> typeTable = (Hashtable<String, AntTypeDefinition>) helper.antTypeTable.clone(); - synchronized (antTypeTable) { - for (AntTypeDefinition def : typeTable.values()) { - antTypeTable.put(def.getName(), def); - } - } - // add the parsed namespaces of the parent project - Set<String> inheritedCheckedNamespace = helper.getCheckedNamespace(); - synchronized (this) { - checkedNamespaces.addAll(inheritedCheckedNamespace); - } - Map<String, List<AntTypeDefinition>> inheritedRestrictedDef = helper.getRestrictedDefinition(); - synchronized (restrictedDefinitions) { - restrictedDefinitions.putAll(inheritedRestrictedDef); - } - } - - /** - * 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 instanceof Task) { - Task task = (Task) component; - task.setLocation(ue.getLocation()); - task.setTaskType(componentType); - task.setTaskName(ue.getTaskName()); - task.setOwningTarget(ue.getOwningTarget()); - task.init(); - } - 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); - return def == null ? null : 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); - return def == null ? null : 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); - return antTypeTable.get(componentName); - } - - /** - * This method is initialization code implementing the original ant component - * loading from /org/apache/tools/ant/taskdefs/default.properties - * and /org/apache/tools/ant/types/default.properties. - */ - public void initDefaultDefinitions() { - initTasks(); - initTypes(); - new DefaultDefinitions(this).execute(); - } - - /** - * 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. - * - * @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((Class[]) 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. Also, the returned table may be - * modified asynchronously. - * - * @return a map of from task name to implementing class - * (String to Class). - */ - public Hashtable<String, Class<?>> getTaskDefinitions() { - synchronized (taskClassDefinitions) { - synchronized (antTypeTable) { - if (rebuildTaskClassDefinitions) { - taskClassDefinitions.clear(); - for (Map.Entry<String, AntTypeDefinition> e : antTypeTable.entrySet()) { - final Class<?> clazz = e.getValue().getExposedClass(project); - if (clazz == null) { - continue; - } - if (Task.class.isAssignableFrom(clazz)) { - taskClassDefinitions.put(e.getKey(), e.getValue().getTypeClass(project)); - } - } - 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<String, Class<?>> getDataTypeDefinitions() { - synchronized (typeClassDefinitions) { - synchronized (antTypeTable) { - if (rebuildTypeClassDefinitions) { - typeClassDefinitions.clear(); - for (Map.Entry<String, AntTypeDefinition> e : antTypeTable.entrySet()) { - final Class<?> clazz = e.getValue().getExposedClass(project); - if (clazz == null) { - continue; - } - if (!Task.class.isAssignableFrom(clazz)) { - typeClassDefinitions.put(e.getKey(), e.getValue().getTypeClass(project)); - } - } - rebuildTypeClassDefinitions = false; - } - } - } - return typeClassDefinitions; - } - - /** - * This returns a list of restricted definitions for a name. - * The returned List is "live" and so should not be modified. - * Also, the returned list may be modified asynchronously. - * Any access must be guarded with a lock on the list itself. - * - * @param componentName the name to use. - * @return the list of restricted definitions for a particular name. - */ - public List<AntTypeDefinition> getRestrictedDefinitions(String componentName) { - synchronized (restrictedDefinitions) { - return restrictedDefinitions.get(componentName); - } - } - - /** - * 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) { - final AntTypeDefinition def = new AntTypeDefinition(); - def.setName(typeName); - def.setClass(typeClass); - updateDataTypeDefinition(def); - project.log(" +User datatype: " + typeName + " " + typeClass.getName(), - Project.MSG_DEBUG); - } - - /** - * Describe <code>addDataTypeDefinition</code> method here. - * - * @param def an <code>AntTypeDefinition</code> value. - */ - public void addDataTypeDefinition(AntTypeDefinition def) { - if (!def.isRestrict()) { - updateDataTypeDefinition(def); - } else { - updateRestrictedDefinition(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 datatype definition - * (String to {@link AntTypeDefinition}). - */ - public Hashtable<String, AntTypeDefinition> getAntTypeTable() { - return antTypeTable; - } - - /** - * Creates a new instance of a task. - * - * Called from Project.createTask(), which can be called by tasks. - * - * @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(ANT_PROPERTY_TASK)) { - // quick fix for Ant.java use of property before - // initializing the project - addTaskDefinition(ANT_PROPERTY_TASK, org.apache.tools.ant.taskdefs.Property.class); - task = createNewTask(taskType); - } - return task; - } - - /** - * Creates a new instance of a task. - * @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 || !(Task.class.isAssignableFrom(c))) { - return null; - } - Object obj = createComponent(taskType); - if (obj == null) { - return null; - } - if (!(obj instanceof Task)) { - throw new BuildException("Expected a Task from '" + taskType - + "' but got an instance of " + obj.getClass().getName() + " instead"); - } - Task task = (Task) obj; - task.setTaskType(taskType); - - // set default value, can be changed by the user - task.setTaskName(taskType); - - project.log(" +Task: " + taskType, Project.MSG_DEBUG); - return task; - } - - /** - * 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) { - return getElementName(element, false); - } - - /** - * Returns a description of the type of the given element. - * <p> - * This is useful for logging purposes. - * - * @param o The element to describe. - * Must not be <code>null</code>. - * @param brief whether to use a brief description. - * @return a description of the element type. - * - * @since Ant 1.7 - */ - public String getElementName(Object o, boolean brief) { - // PR: I do not know what to do if the object class - // has multiple defines - // but this is for logging only... - Class<?> elementClass = o.getClass(); - String elementClassname = elementClass.getName(); - synchronized (antTypeTable) { - for (AntTypeDefinition def : antTypeTable.values()) { - if (elementClassname.equals(def.getClassName()) - && (elementClass == def.getExposedClass(project))) { - String name = def.getName(); - return brief ? name : "The <" + name + "> type"; - } - } - } - return getUnmappedElementName(o.getClass(), brief); - } - - /** - * Convenient way to get some element name even when you may not have a - * Project context. - * @param p The optional Project instance. - * @param o The element to describe. - * Must not be <code>null</code>. - * @param brief whether to use a brief description. - * @return a description of the element type. - * @since Ant 1.7 - */ - public static String getElementName(Project p, Object o, boolean brief) { - if (p == null) { - p = Project.getProject(o); - } - return p == null ? getUnmappedElementName(o.getClass(), brief) : getComponentHelper(p) - .getElementName(o, brief); - } - - private static String getUnmappedElementName(Class<?> c, boolean brief) { - if (brief) { - String name = c.getName(); - return name.substring(name.lastIndexOf('.') + 1); - } - return c.toString(); - } - - /** - * 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) { - return !(def.getTypeClass(project) == null || def.getExposedClass(project) == null); - } - - /** - * 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) { - boolean defValid = validDefinition(def); - boolean sameValidity = (defValid == validDefinition(old)); - //must have same validity; then if they are valid they must also be the same: - return sameValidity && (!defValid || def.sameDefinition(old, project)); - } - - /** - * update the restricted definition table with a new or - * modified definition. - */ - private void updateRestrictedDefinition(AntTypeDefinition def) { - String name = def.getName(); - List<AntTypeDefinition> list = null; - synchronized (restrictedDefinitions) { - list = restrictedDefinitions.get(name); - if (list == null) { - list = new ArrayList<AntTypeDefinition>(); - restrictedDefinitions.put(name, list); - } - } - // Check if the classname is already present and remove it - // if it is - synchronized (list) { - for (Iterator<AntTypeDefinition> i = list.iterator(); i.hasNext();) { - AntTypeDefinition current = i.next(); - if (current.getClassName().equals(def.getClassName())) { - i.remove(); - break; - } - } - list.add(def); - } - } - - /** - * 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; - final AntTypeDefinition old = antTypeTable.get(name); - if (old != null) { - if (sameDefinition(def, old)) { - return; - } - Class<?> oldClass = old.getExposedClass(project); - boolean isTask = oldClass != null && Task.class.isAssignableFrom(oldClass); - project.log("Trying to override old definition of " - + (isTask ? "task " : "datatype ") + name, (def.similarDefinition(old, - project)) ? Project.MSG_VERBOSE : Project.MSG_WARN); - } - 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(); - antLibCurrentUri = (antLibStack.size() == 0) ? null : (String) antLibStack.peek(); - } - - /** - * Load ant's tasks. - */ - private void initTasks() { - ClassLoader classLoader = getClassLoader(null); - Properties props = getDefaultDefinitions(false); - 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); - } - } - - private ClassLoader getClassLoader(ClassLoader classLoader) { - String buildSysclasspath = project.getProperty(MagicNames.BUILD_SYSCLASSPATH); - if (project.getCoreLoader() != null - && !(BUILD_SYSCLASSPATH_ONLY.equals(buildSysclasspath))) { - classLoader = project.getCoreLoader(); - } - return classLoader; - } - - /** - * Load default task or type definitions - just the names, - * no class loading. - * Caches results between calls to reduce overhead. - * @param type true for typedefs, false for taskdefs - * @return a mapping from definition names to class names - * @throws BuildException if there was some problem loading - * or parsing the definitions list - */ - private static synchronized Properties getDefaultDefinitions(boolean type) - throws BuildException { - int idx = type ? 1 : 0; - if (defaultDefinitions[idx] == null) { - String resource = type ? MagicNames.TYPEDEFS_PROPERTIES_RESOURCE - : MagicNames.TASKDEF_PROPERTIES_RESOURCE; - String errorString = type ? ERROR_NO_TYPE_LIST_LOAD : ERROR_NO_TASK_LIST_LOAD; - InputStream in = null; - try { - in = ComponentHelper.class.getResourceAsStream(resource); - if (in == null) { - throw new BuildException(errorString); - } - Properties p = new Properties(); - p.load(in); - defaultDefinitions[idx] = p; - } catch (IOException e) { - throw new BuildException(errorString, e); - } finally { - FileUtils.close(in); - } - } - return defaultDefinitions[idx]; - } - - /** - * Load ant's datatypes. - */ - private void initTypes() { - ClassLoader classLoader = getClassLoader(null); - Properties props = getDefaultDefinitions(true); - 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); - } - } - - /** - * Called for each component name, check if the - * associated URI has been examined for antlibs. - * @param componentName the name of the component, which should include a URI - * prefix if it is in a namespace - */ - private synchronized void checkNamespace(String componentName) { - String uri = ProjectHelper.extractUriFromComponentName(componentName); - if ("".equals(uri)) { - uri = ProjectHelper.ANT_CORE_URI; - } - if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) { - return; // namespace that does not contain antlib - } - if (checkedNamespaces.contains(uri)) { - return; // Already processed - } - checkedNamespaces.add(uri); - - if (antTypeTable.size() == 0) { - // Project instance doesn't know the tasks and types - // defined in defaults.properties, likely created by the - // user - without those definitions it cannot parse antlib - // files as taskdef, typedef and friends are unknown - initDefaultDefinitions(); - } - Typedef definer = new Typedef(); - definer.setProject(project); - definer.init(); - definer.setURI(uri); - //there to stop error messages being "null" - definer.setTaskName(uri); - //if this is left out, bad things happen. like all build files break - //on the first element encountered. - definer.setResource(Definer.makeResourceFromURI(uri)); - // a fishing expedition :- ignore errors if antlib not present - definer.setOnError(new Typedef.OnError(Typedef.OnError.POLICY_IGNORE)); - definer.execute(); - } - - /** - * Handler called to do decent diagnosis on instantiation failure. - * @param componentName component name. - * @param type component type, used in error messages - * @return a string containing as much diagnostics info as possible. - */ - public String diagnoseCreationFailure(String componentName, String type) { - StringWriter errorText = new StringWriter(); - PrintWriter out = new PrintWriter(errorText); - out.println("Problem: failed to create " + type + " " + componentName); - //class of problem - boolean lowlevel = false; - boolean jars = false; - boolean definitions = false; - boolean antTask; - String home = System.getProperty(Launcher.USER_HOMEDIR); - File libDir = new File(home, Launcher.USER_LIBDIR); - String antHomeLib; - boolean probablyIDE = false; - String anthome = System.getProperty(MagicNames.ANT_HOME); - if (anthome != null) { - File antHomeLibDir = new File(anthome, "lib"); - antHomeLib = antHomeLibDir.getAbsolutePath(); - } else { - //running under an IDE that doesn't set ANT_HOME - probablyIDE = true; - antHomeLib = "ANT_HOME" + File.separatorChar + "lib"; - } - StringBuffer dirListingText = new StringBuffer(); - final String tab = " -"; - dirListingText.append(tab); - dirListingText.append(antHomeLib); - dirListingText.append('\n'); - if (probablyIDE) { - dirListingText.append(tab); - dirListingText.append("the IDE Ant configuration dialogs"); - } else { - dirListingText.append(tab); - dirListingText.append(libDir); - dirListingText.append('\n'); - dirListingText.append(tab); - dirListingText.append("a directory added on the command line with the -lib argument"); - } - String dirListing = dirListingText.toString(); - - //look up the name - AntTypeDefinition def = getDefinition(componentName); - if (def == null) { - //not a known type - printUnknownDefinition(out, componentName, dirListing); - definitions = true; - } else { - //we are defined, so it is an instantiation problem - final String classname = def.getClassName(); - antTask = classname.startsWith("org.apache.tools.ant."); - boolean optional = classname.startsWith("org.apache.tools.ant.taskdefs.optional"); - optional |= classname.startsWith("org.apache.tools.ant.types.optional"); - - //start with instantiating the class. - Class<?> clazz = null; - try { - clazz = def.innerGetTypeClass(); - } catch (ClassNotFoundException e) { - jars = true; - if (!optional) { - definitions = true; - } - printClassNotFound(out, classname, optional, dirListing); - } catch (NoClassDefFoundError ncdfe) { - jars = true; - printNotLoadDependentClass(out, optional, ncdfe, dirListing); - } - //here we successfully loaded the class or failed. - if (clazz != null) { - //success: proceed with more steps - try { - def.innerCreateAndSet(clazz, project); - //hey, there is nothing wrong with us - out.println("The component could be instantiated."); - } catch (NoSuchMethodException e) { - lowlevel = true; - out.println("Cause: The class " + classname - + " has no compatible constructor."); - - } catch (InstantiationException e) { - lowlevel = true; - out.println("Cause: The class " + classname - + " is abstract and cannot be instantiated."); - } catch (IllegalAccessException e) { - lowlevel = true; - out.println("Cause: The constructor for " + classname - + " is private and cannot be invoked."); - } catch (InvocationTargetException ex) { - lowlevel = true; - Throwable t = ex.getTargetException(); - out.println("Cause: The constructor threw the exception"); - out.println(t.toString()); - t.printStackTrace(out); - } catch (NoClassDefFoundError ncdfe) { - jars = true; - out.println("Cause: A class needed by class " + classname - + " cannot be found: "); - out.println(" " + ncdfe.getMessage()); - out.println("Action: Determine what extra JAR files are" - + " needed, and place them in:"); - out.println(dirListing); - } - } - out.println(); - out.println("Do not panic, this is a common problem."); - if (definitions) { - out.println("It may just be a typographical error in the build file " - + "or the task/type declaration."); - } - if (jars) { - out.println("The commonest cause is a missing JAR."); - } - if (lowlevel) { - out.println("This is quite a low level problem, which may need " - + "consultation with the author of the task."); - if (antTask) { - out.println("This may be the Ant team. Please file a " - + "defect or contact the developer team."); - } else { - out.println("This does not appear to be a task bundled with Ant."); - out.println("Please take it up with the supplier of the third-party " + type - + "."); - out.println("If you have written it yourself, you probably have a bug to fix."); - } - } else { - out.println(); - out.println("This is not a bug; it is a configuration problem"); - } - } - out.flush(); - out.close(); - return errorText.toString(); - } - - /** - * Print unknown definition.forking - */ - private void printUnknownDefinition(PrintWriter out, String componentName, String dirListing) { - boolean isAntlib = componentName.startsWith(MagicNames.ANTLIB_PREFIX); - String uri = ProjectHelper.extractUriFromComponentName(componentName); - out.println("Cause: The name is undefined."); - out.println("Action: Check the spelling."); - out.println("Action: Check that any custom tasks/types have been declared."); - out.println("Action: Check that any <presetdef>/<macrodef>" - + " declarations have taken place."); - if (uri.length() > 0) { - final List<AntTypeDefinition> matches = findTypeMatches(uri); - if (matches.size() > 0) { - out.println(); - out.println("The definitions in the namespace " + uri + " are:"); - for (AntTypeDefinition def : matches) { - String local = ProjectHelper.extractNameFromComponentName(def.getName()); - out.println(" " + local); - } - } else { - out.println("No types or tasks have been defined in this namespace yet"); - if (isAntlib) { - out.println(); - out.println("This appears to be an antlib declaration. "); - out.println("Action: Check that the implementing library exists in one of:"); - out.println(dirListing); - } - } - } - } - - /** - * Print class not found. - */ - private void printClassNotFound(PrintWriter out, String classname, boolean optional, - String dirListing) { - out.println("Cause: the class " + classname + " was not found."); - if (optional) { - out.println(" This looks like one of Ant's optional components."); - out.println("Action: Check that the appropriate optional JAR exists in"); - out.println(dirListing); - } else { - out.println("Action: Check that the component has been correctly declared"); - out.println(" and that the implementing JAR is in one of:"); - out.println(dirListing); - } - } - - /** - * Print could not load dependent class. - */ - private void printNotLoadDependentClass(PrintWriter out, boolean optional, - NoClassDefFoundError ncdfe, String dirListing) { - out.println("Cause: Could not load a dependent class " - + ncdfe.getMessage()); - if (optional) { - out.println(" It is not enough to have Ant's optional JARs"); - out.println(" you need the JAR files that the" + " optional tasks depend upon."); - out.println(" Ant's optional task dependencies are" + " listed in the manual."); - } else { - out.println(" This class may be in a separate JAR" + " that is not installed."); - } - out.println("Action: Determine what extra JAR files are" - + " needed, and place them in one of:"); - out.println(dirListing); - } - - /** - * Create a list of all definitions that match a prefix, usually the URI - * of a library - * @param prefix prefix to match off - * @return the (possibly empty) list of definitions - */ - private List<AntTypeDefinition> findTypeMatches(String prefix) { - final List<AntTypeDefinition> result = new ArrayList<AntTypeDefinition>(); - synchronized (antTypeTable) { - for (AntTypeDefinition def : antTypeTable.values()) { - if (def.getName().startsWith(prefix)) { - result.add(def); - } - } - } - return result; - } -} |