stevel 2005/03/01 06:55:47
Modified: src/main/org/apache/tools/ant AntTypeDefinition.java
MagicNames.java ComponentHelper.java
Diagnostics.java UnknownElement.java
src/main/org/apache/tools/ant/launch Launcher.java
Log:
complete rework of reporting when we cant instantiate an element
old: generic error message
new: step by step diagnostics with instructions.
The code treats ant tasks and ant optional tasks specially, based on package
names.
Also: moved some constants into the appropriate places.
Revision Changes Path
1.16 +73 -25 ant/src/main/org/apache/tools/ant/AntTypeDefinition.java
Index: AntTypeDefinition.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/AntTypeDefinition.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- AntTypeDefinition.java 15 Dec 2004 23:44:05 -0000 1.15
+++ AntTypeDefinition.java 1 Mar 2005 14:55:46 -0000 1.16
@@ -17,6 +17,9 @@
package org.apache.tools.ant;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Constructor;
+
/**
* This class contains all the information
@@ -143,15 +146,8 @@
* @return the type of the definition.
*/
public Class getTypeClass(Project project) {
- if (clazz != null) {
- return clazz;
- }
try {
- if (classLoader == null) {
- clazz = Class.forName(className);
- } else {
- clazz = classLoader.loadClass(className);
- }
+ return innerGetTypeClass();
} catch (NoClassDefFoundError ncdfe) {
project.log("Could not load a dependent class ("
+ ncdfe.getMessage() + ") for type "
@@ -160,6 +156,24 @@
project.log("Could not load class (" + className
+ ") for type " + name, Project.MSG_DEBUG);
}
+ return null;
+ }
+
+ /**
+ * Try and load a class, with no attempt to catch any fault.
+ * @return the class that implements this component
+ * @throws ClassNotFoundException
+ * @throws NoClassDefFoundError
+ */
+ public Class innerGetTypeClass() throws ClassNotFoundException {
+ if (clazz != null) {
+ return clazz;
+ }
+ if (classLoader == null) {
+ clazz = Class.forName(className);
+ } else {
+ clazz = classLoader.loadClass(className);
+ }
return clazz;
}
@@ -238,23 +252,9 @@
*/
private Object createAndSet(Project project, Class c) {
try {
- java.lang.reflect.Constructor ctor = null;
- boolean noArg = false;
- // DataType can have a "no arg" constructor or take a single
- // Project argument.
- try {
- ctor = c.getConstructor(new Class[0]);
- noArg = true;
- } catch (NoSuchMethodException nse) {
- ctor = c.getConstructor(new Class[] {Project.class});
- noArg = false;
- }
- Object o = ctor.newInstance(
- ((noArg) ? new Object[0] : new Object[] {project}));
-
- project.setProjectReference(o);
+ Object o = innerCreateAndSet(c, project);
return o;
- } catch (java.lang.reflect.InvocationTargetException ex) {
+ } catch (InvocationTargetException ex) {
Throwable t = ex.getTargetException();
throw new BuildException(
"Could not create type " + name + " due to " + t, t);
@@ -262,13 +262,61 @@
String msg = "Type " + name + ": A class needed by class "
+ c + " cannot be found: " + ncdfe.getMessage();
throw new BuildException(msg, ncdfe);
- } catch (Throwable t) {
+ } catch (NoSuchMethodException nsme) {
+ throw new BuildException("Could not create type " + name
+ + " as the class " + c +" has no compatible constructor"
);
+ } catch (InstantiationException nsme) {
+ throw new BuildException("Could not create type " +
+ name
+ + " as the class " + c + " is abstract");
+ } catch(IllegalAccessException e) {
+ throw new BuildException("Could not create type " +
+ name
+ + " as the constructor " + c + " is not accessible");
+ } catch (Throwable t) {
throw new BuildException(
"Could not create type " + name + " due to " + t, t);
}
}
/**
+ * Inner implementation of the [EMAIL PROTECTED] #createAndSet} logic,
with no
+ * exception catching
+ * @param newclass class to create
+ * @param project
+ * @return a newly constructed and bound instance.
+ * @throws NoSuchMethodException
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public Object innerCreateAndSet(Class newclass, Project project)
+ throws NoSuchMethodException,
+ InstantiationException,
+ IllegalAccessException,
+ InvocationTargetException {
+ Constructor ctor = null;
+ boolean noArg = false;
+ // DataType can have a "no arg" constructor or take a single
+ // Project argument.
+ try {
+ ctor = newclass.getConstructor(new Class[0]);
+ noArg = true;
+ } catch (NoSuchMethodException nse) {
+ //can throw the same exception, if there is no this(Project)
ctor.
+ ctor = newclass.getConstructor(new Class[] {Project.class});
+ noArg = false;
+ }
+ //now we instantiate
+ Object o = ctor.newInstance(
+ ((noArg) ? new Object[0] : new Object[] {project}));
+
+ //set up project references.
+ project.setProjectReference(o);
+ return o;
+ }
+
+ /**
* Equality method for this definition (assumes the names are the same).
*
* @param other another definition.
1.7 +34 -2 ant/src/main/org/apache/tools/ant/MagicNames.java
Index: MagicNames.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/MagicNames.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- MagicNames.java 9 Mar 2004 16:47:59 -0000 1.6
+++ MagicNames.java 1 Mar 2005 14:55:46 -0000 1.7
@@ -24,11 +24,43 @@
* @since Ant 1.6
*/
public class MagicNames {
- /** The name of the script repository used by the script repo task */
+ /**
+ * The name of the script repository used by the script repo task
+ * Value [EMAIL PROTECTED]
+ */
public static final String SCRIPT_REPOSITORY =
"org.apache.ant.scriptrepo";
- /** The name of the reference to the System Class Loader */
+ /**
+ * The name of the reference to the System Class Loader
+ * Value [EMAIL PROTECTED]
+ **/
public static final String SYSTEM_LOADER_REF = "ant.coreLoader";
+ /**
+ * Name of the property which can provide an override of the repository
dir
+ * for the libraries task
+ * Value [EMAIL PROTECTED]
+ */
+ public static final String REPOSITORY_DIR_PROPERTY =
"ant.maven.repository.dir";
+ /**
+ * Name of the property which can provide an override of the repository
URL
+ * for the libraries task
+ * Value [EMAIL PROTECTED]
+ */
+ public static final String REPOSITORY_URL_PROPERTY =
"ant.maven.repository.url";
+
+ /**
+ * name of the resource that taskdefs are stored under
+ * Value: [EMAIL PROTECTED]
+ */
+ public static final String TASKDEF_PROPERTIES_RESOURCE =
+ "/org/apache/tools/ant/taskdefs/defaults.properties";
+ /**
+ * name of the resource that typedefs are stored under
+ * Value: [EMAIL PROTECTED]
+ */
+ public static final String TYPEDEFS_PROPERTIES_RESOURCE =
+ "/org/apache/tools/ant/types/defaults.properties";
+
}
1.49 +156 -8 ant/src/main/org/apache/tools/ant/ComponentHelper.java
Index: ComponentHelper.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/ComponentHelper.java,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -r1.48 -r1.49
--- ComponentHelper.java 28 Jan 2005 16:01:07 -0000 1.48
+++ ComponentHelper.java 1 Mar 2005 14:55:46 -0000 1.49
@@ -28,10 +28,15 @@
import java.util.Vector;
import java.io.InputStream;
import java.io.IOException;
+import java.io.File;
+import java.io.StringWriter;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
import org.apache.tools.ant.taskdefs.Typedef;
+import org.apache.tools.ant.launch.Launcher;
/**
* Component creation and configuration.
@@ -83,6 +88,9 @@
private ComponentHelper next;
private Project project;
+ private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load
default task list";
+ private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load
default type list";
+ public static final String COMPONENT_HELPER_REFERENCE =
"ant.ComponentHelper";
/**
* Find a project component for a specific project, creating
@@ -93,14 +101,14 @@
public static ComponentHelper getComponentHelper(Project project) {
// Singleton for now, it may change ( per/classloader )
ComponentHelper ph = (ComponentHelper) project.getReference(
- "ant.ComponentHelper");
+ COMPONENT_HELPER_REFERENCE);
if (ph != null) {
return ph;
}
ph = new ComponentHelper();
ph.setProject(project);
- project.addReference("ant.ComponentHelper", ph);
+ project.addReference(COMPONENT_HELPER_REFERENCE, ph);
return ph;
}
@@ -654,14 +662,14 @@
&& !("only".equals(project.getProperty("build.sysclasspath")))) {
classLoader = project.getCoreLoader();
}
- String dataDefs =
"/org/apache/tools/ant/taskdefs/defaults.properties";
+ String dataDefs = MagicNames.TASKDEF_PROPERTIES_RESOURCE;
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");
+ throw new BuildException(ERROR_NO_TASK_LIST_LOAD);
}
props.load(in);
@@ -678,7 +686,7 @@
antTypeTable.put(name, def);
}
} catch (IOException ex) {
- throw new BuildException("Can't load default type list");
+ throw new BuildException(ERROR_NO_TASK_LIST_LOAD);
} finally {
if (in != null) {
try {
@@ -699,14 +707,14 @@
&& !("only".equals(project.getProperty("build.sysclasspath")))) {
classLoader = project.getCoreLoader();
}
- String dataDefs = "/org/apache/tools/ant/types/defaults.properties";
+ String dataDefs = MagicNames.TYPEDEFS_PROPERTIES_RESOURCE;
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");
+ throw new BuildException(ERROR_NO_TYPE_LIST_LOAD);
}
props.load(in);
@@ -721,7 +729,7 @@
antTypeTable.put(name, def);
}
} catch (IOException ex) {
- throw new BuildException("Can't load default type list");
+ throw new BuildException(ERROR_NO_TYPE_LIST_LOAD);
} finally {
if (in != null) {
try {
@@ -762,6 +770,146 @@
}
/**
+ * Handler called to do decent diagnosis on instantiation failure
+ * @param componentName
+ * @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;
+ //look up the name
+ AntTypeDefinition def = getDefinition(componentName);
+ if(def==null) {
+ //not a known type
+ 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>/<macrodefs>
declarations have taken place");
+ 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");
+ String home = System.getProperty(Launcher.USER_HOMEDIR);
+ File libDir = new File(home,
+ Launcher.ANT_PRIVATEDIR +
+ File.separator +
+ Launcher.ANT_PRIVATELIB);
+
+ //start with instantiating the class.
+ Class clazz= null;
+ try {
+ clazz = def.innerGetTypeClass();
+ } catch (ClassNotFoundException e) {
+ out.println("Cause: the class " +
+ classname
+ + " was not found");
+ jars = true;
+ if (optional) {
+ out.println(" This looks like one of Ant's
optional components");
+ out.println("Action: check that the appropriate optional
JAR exists "
+ + "in ANT_HOME/lib or in ");
+ out.println(" " + libDir);
+ } else {
+ out.println("Action: check that the component has been
correctly declared");
+ out.println(" And that the implementing JAR is in
ANT_HOME/lib or in");
+ out.println(" " + libDir);
+ definitions = true;
+ }
+ } catch (NoClassDefFoundError ncdfe) {
+ jars = true;
+ out.println("Cause: Could not load a dependent class "
+ + ncdfe.getMessage());
+ if(optional) {
+ out.println(" It is not enough to have Ant's
optional JAR, you need the JAR");
+ out.println(" files that it depends 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");
+ out.println(" In ANT_HOME/lib or");
+ out.println(" in " + libDir );
+ }
+ //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");
+ out.println(" In ANT_HOME/lib or");
+ out.println(" in " + libDir);
+ }
+ }
+ out.println();
+ out.println("Do not panic, this is a common problem.");
+ if(definitions) {
+ out.println("It may just be a typing 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("It is not an Ant bug; there is no need to file
a bug" +
+ " report or contact the developers");
+ }
+
+ }
+ out.flush();
+ out.close();
+ return errorText.toString();
+ }
+
+ /**
* Map that contains the component definitions.
*/
private static class AntTypeTable extends Hashtable {
1.22 +4 -5 ant/src/main/org/apache/tools/ant/Diagnostics.java
Index: Diagnostics.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Diagnostics.java,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -r1.21 -r1.22
--- Diagnostics.java 8 Feb 2005 18:50:35 -0000 1.21
+++ Diagnostics.java 1 Mar 2005 14:55:46 -0000 1.22
@@ -72,7 +72,7 @@
public static void validateVersion() throws BuildException {
try {
Class optional
- =
Class.forName("org.apache.tools.ant.taskdefs.optional.Test");
+ = Class.forName(TEST_CLASS);
String coreVersion = getImplementationVersion(Main.class);
String optionalVersion = getImplementationVersion(optional);
@@ -94,7 +94,7 @@
* <tt>null</tt> if an error occurs.
*/
public static File[] listLibraries() {
- String home = System.getProperty("ant.home");
+ String home = System.getProperty(Launcher.ANTHOME_PROPERTY);
if (home == null) {
return null;
}
@@ -211,8 +211,7 @@
Class optional = null;
try {
- optional = Class.forName(
- "org.apache.tools.ant.taskdefs.optional.Test");
+ optional = Class.forName(TEST_CLASS);
out.println("optional tasks : "
+ getImplementationVersion(optional));
} catch (ClassNotFoundException e) {
@@ -340,7 +339,7 @@
*/
private static void doReportTasksAvailability(PrintStream out) {
InputStream is = Main.class.getResourceAsStream(
- "/org/apache/tools/ant/taskdefs/defaults.properties");
+ MagicNames.TASKDEF_PROPERTIES_RESOURCE);
if (is == null) {
out.println("None available");
} else {
1.86 +2 -39 ant/src/main/org/apache/tools/ant/UnknownElement.java
Index: UnknownElement.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/UnknownElement.java,v
retrieving revision 1.85
retrieving revision 1.86
diff -u -r1.85 -r1.86
--- UnknownElement.java 22 Feb 2005 15:30:19 -0000 1.85
+++ UnknownElement.java 1 Mar 2005 14:55:46 -0000 1.86
@@ -463,45 +463,8 @@
*/
protected BuildException getNotFoundException(String what,
String elementName) {
- String lSep = System.getProperty("line.separator");
- String msg = "Could not create " + what + " of type: " + elementName
- + "." + lSep + lSep
- + "Ant could not find the task or a class this "
- + "task relies upon." + lSep + lSep
- + "This is common and has a number of causes; the usual " + lSep
- + "solutions are to read the manual pages then download and" +
lSep
- + "install needed JAR files, or fix the build file: " + lSep
- + " - You have misspelt '" + elementName + "'." + lSep
- + " Fix: check your spelling." + lSep
- + " - The task needs an external JAR file to execute" + lSep
- + " and this is not found at the right place in the
classpath." + lSep
- + " Fix: check the documentation for dependencies." + lSep
- + " Fix: declare the task." + lSep
- + " - The task is an Ant optional task and the JAR file and/or
libraries" + lSep
- + " implementing the functionality were not found at the
time you" + lSep
- + " yourself built your installation of Ant from the Ant
sources." + lSep
- + " Fix: Look in the ANT_HOME/lib for the 'ant-' JAR
corresponding to the" + lSep
- + " task and make sure it contains more than merely a
META-INF/MANIFEST.MF." + lSep
- + " If all it contains is the manifest, then rebuild Ant
with the needed" + lSep
- + " libraries present in ${ant.home}/lib/optional/ , or
alternatively," + lSep
- + " download a pre-built release version from apache.org" +
lSep
- + " - The build file was written for a later version of Ant" +
lSep
- + " Fix: upgrade to at least the latest release version of
Ant" + lSep
- + " - The task is not an Ant core or optional task " + lSep
- + " and needs to be declared using <taskdef>." + lSep
- + " - You are attempting to use a task defined using " + lSep
- + " <presetdef> or <macrodef> but have spelt wrong or not " +
lSep
- + " defined it at the point of use" + lSep
- + lSep
- + "Remember that for JAR files to be visible to Ant tasks
implemented" + lSep
- + "in ANT_HOME/lib, the files must be in the same directory or
on the" + lSep
- + "classpath" + lSep
- + lSep
- + "Please neither file bug reports on this problem, nor email
the" + lSep
- + "Ant mailing lists, until all of these causes have been
explored," + lSep
- + "as this is not an Ant bug.";
-
-
+ ComponentHelper helper =
ComponentHelper.getComponentHelper(getProject());
+ String msg = helper.diagnoseCreationFailure(elementName, what);
return new BuildException(msg, getLocation());
}
1.29 +4 -1 ant/src/main/org/apache/tools/ant/launch/Launcher.java
Index: Launcher.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/launch/Launcher.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- Launcher.java 2 Feb 2005 09:09:12 -0000 1.28
+++ Launcher.java 1 Mar 2005 14:55:47 -0000 1.29
@@ -32,7 +32,10 @@
* @since Ant 1.6
*/
public class Launcher {
- /** The Ant Home property */
+ /**
+ * Ant home directory
+ * Value : [EMAIL PROTECTED]
+ */
public static final String ANTHOME_PROPERTY = "ant.home";
/** The Ant Library Directory property */
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]