diff --git a/build.xml b/build.xml
index 7df16e303..be44ea57a 100644
--- a/build.xml
+++ b/build.xml
@@ -212,15 +212,7 @@
-
-
-
-
-
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
index aa05ae31d..8e9672f86 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
@@ -210,25 +210,25 @@ public class EjbJar extends MatchingTask {
* Naming scheme where generated jar is determined from the ejb-name in
* the deployment descripor
*/
- public final static String EJB_NAME = "ejb-name";
+ public static final String EJB_NAME = "ejb-name";
/**
* Naming scheme where the generated jar name is based on the
* name of the directory containing the deployment descriptor
*/
- public final static String DIRECTORY = "directory";
+ public static final String DIRECTORY = "directory";
/**
* Naming scheme where the generated jar name is based on the name of
* the deployment descriptor file
*/
- public final static String DESCRIPTOR = "descriptor";
+ public static final String DESCRIPTOR = "descriptor";
/**
* Naming scheme where the generated jar is named by the basejarname
* attribute
*/
- public final static String BASEJARNAME = "basejarname";
+ public static final String BASEJARNAME = "basejarname";
/**
* Gets the values of the NamingScheme
@@ -451,8 +451,7 @@ public class EjbJar extends MatchingTask {
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.BASEJARNAME);
- }
- else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
+ } else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
throw new BuildException("The basejarname attribute is not compatible with the " +
config.namingScheme.getValue() + " naming scheme");
}
@@ -543,7 +542,7 @@ public class EjbJar extends MatchingTask {
*
* @throws BuildException if the config is not valid
*/
- private void validateConfig() {
+ private void validateConfig() throws BuildException {
if (config.srcDir == null) {
throw new BuildException("The srcDir attribute must be specified");
}
@@ -555,8 +554,7 @@ public class EjbJar extends MatchingTask {
if (config.namingScheme == null) {
config.namingScheme = new NamingScheme();
config.namingScheme.setValue(NamingScheme.DESCRIPTOR);
- }
- else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME) &&
+ } else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME) &&
config.baseJarName == null) {
throw new BuildException("The basejarname attribute must be specified " +
"with the basejarname naming scheme");
@@ -618,14 +616,12 @@ public class EjbJar extends MatchingTask {
tool.processDescriptor(files[index], saxParser);
}
}
- }
- catch (SAXException se) {
+ } catch (SAXException se) {
String msg = "SAXException while creating parser."
+ " Details: "
+ se.getMessage();
throw new BuildException(msg, se);
- }
- catch (ParserConfigurationException pce) {
+ } catch (ParserConfigurationException pce) {
String msg = "ParserConfigurationException while creating parser. "
+ "Details: " + pce.getMessage();
throw new BuildException(msg, pce);
diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
index 8f9578ad5..bbb9e95a2 100644
--- a/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
+++ b/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
@@ -68,20 +68,17 @@ import java.util.ArrayList;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
+import java.util.Enumeration;
import javax.xml.parsers.SAXParser;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-
-
-import org.apache.tools.ant.util.depend.Dependencies;
-import org.apache.tools.ant.util.depend.Filter;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.ClassParser;
-
import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Location;
@@ -99,16 +96,23 @@ import org.apache.tools.ant.types.FileSet;
* This class is also used as a framework for the creation of vendor specific
* deployment tools. A number of template methods are provided through which the
* vendor specific tool can hook into the EJB creation process.
+ *
+ * @author Conor MacNeill
*/
public class GenericDeploymentTool implements EJBDeploymentTool {
- /** Private constants that are used when constructing the standard jarfile */
- protected final static String META_DIR = "META-INF/";
- protected final static String EJB_DD = "ejb-jar.xml";
-
+ /** The standard META-INF directory in jar files */
+ protected static final String META_DIR = "META-INF/";
+
+ /** Name for EJB Deployment descriptor within EJB jars */
+ protected static final String EJB_DD = "ejb-jar.xml";
+
+ public static final String DEFAULT_ANALYZER_CLASS
+ = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
+
/**
- * The configuration from the containing task. This config combined with the
- * settings of the individual attributes here constitues the complete config for
- * this deployment tool.
+ * The configuration from the containing task. This config combined
+ * with the settings of the individual attributes here constitues the
+ * complete config for this deployment tool.
*/
private EjbJar.Config config;
@@ -123,8 +127,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
private String genericJarSuffix = "-generic.jar";
/**
- * The task to which this tool belongs. This is used to access services provided
- * by the ant core, such as logging.
+ * The task to which this tool belongs. This is used to access services
+ * provided by the ant core, such as logging.
*/
private Task task;
@@ -145,8 +149,25 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
private DescriptorHandler handler;
/**
- * Setter used to store the value of destination directory prior to execute()
- * being called.
+ * Dependency analyzer used to collect class dependencies
+ */
+ private DependencyAnalyzer dependencyAnalyzer;
+
+ public GenericDeploymentTool() {
+ String analyzerClassName = DEFAULT_ANALYZER_CLASS;
+ try {
+ Class analyzerClass = Class.forName(analyzerClassName);
+ dependencyAnalyzer = (DependencyAnalyzer)analyzerClass.newInstance();
+ } catch (Exception e) {
+ task.log("Unable to load dependency analyzer: " + analyzerClassName,
+ Project.MSG_VERBOSE);
+ }
+ }
+
+
+ /**
+ * Setter used to store the value of destination directory prior to
+ * execute() being called.
* @param inDir the destination directory.
*/
public void setDestdir(File inDir) {
@@ -155,6 +176,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Get the desitination directory.
+ *
+ * @return the destination directory into which EJB jars are to be written
*/
protected File getDestDir() {
return destDir;
@@ -163,6 +186,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Set the task which owns this tool
+ *
+ * @param task the Task to which this deployment tool is associated.
*/
public void setTask(Task task) {
this.task = task;
@@ -170,6 +195,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Get the task for this tool.
+ *
+ * @return the Task instance this tool is associated with.
*/
protected Task getTask() {
return task;
@@ -177,13 +204,18 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Get the basename terminator.
+ *
+ * @return an ejbjar task configuration
*/
protected EjbJar.Config getConfig() {
return config;
}
/**
- * Returns true, if the meta-inf dir is being explicitly set, false otherwise.
+ * Indicate if this build is using the base jar name.
+ *
+ * @return true if the name of the generated jar is coming from the
+ * basejarname attribute
*/
protected boolean usingBaseJarName() {
return config.baseJarName != null;
@@ -199,6 +231,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Add the classpath for the user classes
+ *
+ * @return a Path instance to be configured by Ant.
*/
public Path createClasspath() {
if (classpath == null) {
@@ -209,6 +243,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Set the classpath to be used for this compilation.
+ *
+ * @param classpath the classpath to be used for this build.
*/
public void setClasspath(Path classpath) {
this.classpath = classpath;
@@ -217,14 +253,15 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Get the classpath by combining the one from the surrounding task, if any
* and the one from this tool.
+ *
+ * @return the combined classpath
*/
protected Path getCombinedClasspath() {
Path combinedPath = classpath;
if (config.classpath != null) {
if (combinedPath == null) {
combinedPath = config.classpath;
- }
- else {
+ } else {
combinedPath.append(config.classpath);
}
}
@@ -232,10 +269,21 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
return combinedPath;
}
+ /**
+ * Log a message to the Ant output.
+ *
+ * @param message the message to be logged.
+ * @param level the severity of this message.
+ */
protected void log(String message, int level) {
getTask().log(message, level);
}
+ /**
+ * Get the build file location associated with this element's task.
+ *
+ * @return the task's location instance.
+ */
protected Location getLocation() {
return getTask().getLocation();
}
@@ -243,10 +291,15 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
/**
* Configure this tool for use in the ejbjar task.
+ *
+ * @param config the configuration from the surrounding ejbjar task.
*/
public void configure(EjbJar.Config config) {
this.config = config;
-
+ dependencyAnalyzer.addClassPath(new Path(task.getProject(),
+ config.srcDir.getPath()));
+ dependencyAnalyzer.addClassPath(config.classpath);
+
classpathLoader = null;
}
@@ -271,7 +324,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
if (!addedfiles.contains(logicalFilename)) {
iStream = new FileInputStream(inputFile);
// Create the zip entry and add it to the jar file
- ZipEntry zipEntry = new ZipEntry(logicalFilename.replace('\\','/'));
+ ZipEntry zipEntry = new ZipEntry(logicalFilename.replace('\\', '/'));
jStream.putNextEntry(zipEntry);
// Create the file input stream, and buffer everything over
@@ -286,19 +339,16 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
//add it to list of files in jar
addedfiles.add(logicalFilename);
}
- }
- catch (IOException ioe) {
+ } catch (IOException ioe) {
log("WARNING: IOException while adding entry " +
logicalFilename + " to jarfile from " + inputFile.getPath() + " " +
ioe.getClass().getName() + "-" + ioe.getMessage(), Project.MSG_WARN);
- }
- finally {
+ } finally {
// Close up the file input stream for the class file
if (iStream != null) {
try {
iStream.close();
- }
- catch (IOException closeException) {}
+ } catch (IOException closeException) {}
}
}
}
@@ -383,23 +433,20 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
String publicId = getPublicId();
writeJar(baseName, jarFile, ejbFiles, publicId);
- }
- else {
+ } else {
// Log that the file is up to date...
log(jarFile.toString() + " is up to date.",
Project.MSG_VERBOSE);
}
- }
- catch (SAXException se) {
+ } catch (SAXException se) {
String msg = "SAXException while parsing '"
+ descriptorFileName.toString()
+ "'. This probably indicates badly-formed XML."
+ " Details: "
+ se.getMessage();
throw new BuildException(msg, se);
- }
- catch (IOException ioe) {
+ } catch (IOException ioe) {
String msg = "IOException while parsing'"
+ descriptorFileName.toString()
+ "'. This probably indicates that the descriptor"
@@ -466,8 +513,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
if (descriptorStream != null) {
try {
descriptorStream.close();
- }
- catch (IOException closeException) {}
+ } catch (IOException closeException) {}
}
}
@@ -566,8 +612,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
int index = canonicalDescriptor.lastIndexOf('/');
if (index == -1) {
ddPrefix = "";
- }
- else {
+ } else {
ddPrefix = descriptorFileName.substring(0, index + 1);
}
}
@@ -622,7 +667,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
// Loop through the files seeing if any has been touched
// more recently than the destination jar.
- while(fileIter.hasNext()) {
+ while (fileIter.hasNext()) {
File currentFile = (File) fileIter.next();
if (lastBuild < currentFile.lastModified()) {
log("Build needed because " + currentFile.getPath() + " is out of date",
@@ -641,7 +686,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
* every vendor-specific DeploymentTool
will need to reference
* this value or may want to determine this value in a vendor-specific way.
*
- * @return Public ID of the DTD specified in the EJB descriptor.
+ * @return Public ID of the DTD specified in the EJB descriptor.
*/
protected String getPublicId() {
return handler.getPublicId();
@@ -677,15 +722,13 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
File manifestFile = new File(getConfig().descriptorDir, baseName + "-manifest.mf");
if (manifestFile.exists()) {
in = new FileInputStream(manifestFile);
- }
- else if (config.manifest != null) {
+ } else if (config.manifest != null) {
in = new FileInputStream(config.manifest);
if ( in == null ) {
throw new BuildException("Could not find manifest file: " + config.manifest,
getLocation());
}
- }
- else {
+ } else {
String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf";
in = this.getClass().getResourceAsStream(defaultManifest);
if ( in == null ) {
@@ -695,11 +738,9 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
}
manifest = new Manifest(in);
- }
- catch (IOException e) {
+ } catch (IOException e) {
throw new BuildException ("Unable to read manifest", e, getLocation());
- }
- finally {
+ } finally {
if (in != null) {
in.close();
}
@@ -728,11 +769,10 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
for (int i = 0, n = innerfiles.length; i < n; i++) {
//get and clean up innerclass name
- int entryIndex = entryName.lastIndexOf(entryFile.getName()) -1;
+ int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1;
if ( entryIndex < 0) {
entryName = innerfiles[i];
- }
- else {
+ } else {
entryName = entryName.substring(0, entryIndex) + File.separatorChar + innerfiles[i];
}
// link the file
@@ -746,20 +786,17 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
}
}
}
- }
- catch(IOException ioe) {
+ } catch (IOException ioe) {
String msg = "IOException while processing ejb-jar file '"
+ jarfile.toString()
+ "'. Details: "
+ ioe.getMessage();
throw new BuildException(msg, ioe);
- }
- finally {
+ } finally {
if (jarStream != null) {
try {
jarStream.close();
- }
- catch (IOException closeException) {}
+ } catch (IOException closeException) {}
}
}
} // end of writeJar
@@ -770,55 +807,35 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
* @param checkEntries files, that are extracted from the deployment descriptor
*/
protected void checkAndAddDependants(Hashtable checkEntries)
- throws BuildException
- {
- Dependencies visitor = new Dependencies();
- Set set = new TreeSet();
- Set newSet = new HashSet();
- final String base = config.srcDir.getAbsolutePath() + File.separator;
+ throws BuildException {
+ dependencyAnalyzer.reset();
+
Iterator i = checkEntries.keySet().iterator();
while (i.hasNext()) {
String entryName = (String)i.next();
if (entryName.endsWith(".class")) {
- newSet.add(entryName.substring(0, entryName.length() - ".class".length()).replace(File.separatorChar, '/'));
+ String className = entryName.substring(0,
+ entryName.length() - ".class".length());
+ className = className.replace(File.separatorChar, '/');
+ className = className.replace('/', '.');
+
+ dependencyAnalyzer.addRootClass(className);
}
}
- set.addAll(newSet);
-
- do {
- i = newSet.iterator();
- while (i.hasNext()) {
- String fileName = base + ((String)i.next()).replace('/', File.separatorChar) + ".class";
-
- try {
- JavaClass javaClass = new ClassParser(fileName).parse();
- javaClass.accept(visitor);
- }
- catch (IOException e) {
- log("exception: " + e.getMessage(), Project.MSG_INFO);
- }
+
+ Enumeration e = dependencyAnalyzer.getClassDependencies();
+
+ while (e.hasMoreElements()) {
+ String classname = (String)e.nextElement();
+ String location
+ = classname.replace('.', File.separatorChar) + ".class";
+ File classFile = new File(config.srcDir, location);
+ if (classFile.exists()) {
+ checkEntries.put(location, classFile);
+ log("dependent class: " + classname + " - " + classFile,
+ Project.MSG_VERBOSE);
}
- newSet.clear();
- newSet.addAll(visitor.getDependencies());
- visitor.clearDependencies();
-
- Dependencies.applyFilter(newSet, new Filter() {
- public boolean accept(Object object) {
- String fileName = base + ((String)object).replace('/', File.separatorChar) + ".class";
- return new File(fileName).exists();
- }
- });
- newSet.removeAll(set);
- set.addAll(newSet);
- }
- while (newSet.size() > 0);
-
- i = set.iterator();
- while (i.hasNext()) {
- String next = ((String)i.next()).replace('/', File.separatorChar);
- checkEntries.put(next + ".class", new File(base + next + ".class"));
- log("dependent class: " + next + ".class" + " - " + base + next + ".class", Project.MSG_VERBOSE);
}
}
@@ -829,8 +846,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
* being added to the jar.
*
*/
- protected ClassLoader getClassLoaderForBuild()
- {
+ protected ClassLoader getClassLoaderForBuild() {
if (classpathLoader != null) {
return classpathLoader;
}
@@ -840,8 +856,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool {
// only generate a new ClassLoader if we have a classpath
if (combinedClasspath == null) {
classpathLoader = getClass().getClassLoader();
- }
- else {
+ } else {
classpathLoader = new AntClassLoader(getTask().getProject(), combinedClasspath);
}
diff --git a/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java b/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java
index 775bd9db7..e0175a180 100644
--- a/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java
+++ b/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java
@@ -55,52 +55,87 @@ package org.apache.tools.ant.types.optional.depend;
-import java.util.List;
-import java.util.ArrayList;
-import org.apache.tools.ant.BuildException;
+import java.util.Vector;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;
/**
- * A DepSet is a FileSet, that enlists all classes that depend on a
- * certain class.
+ * A ClassfileSet is a FileSet, that enlists all classes that depend on a
+ * certain set of root classes.
*
- * A DependSet extends FileSets and uses another FileSet as input. The
+ * A ClassfileSet extends FileSets. The
* nested FileSet attribute provides the domain, that is used for searching
* for dependent classes
*
* @author Holger Engels
*/
public class ClassfileSet extends FileSet {
- private List rootClasses = new ArrayList();
+ /**
+ * The list of root classes for this class file set. These are the
+ * classes which must be included in the fileset and which are the
+ * starting point for the dependency search.
+ */
+ private Vector rootClasses = new Vector();
+ /**
+ * Inner class used to contain info about root classes
+ */
public static class ClassRoot {
+ /** The name of the root class */
private String rootClass;
+ /**
+ * Set the root class name
+ *
+ * @param name the name of the root class
+ */
public void setClassname(String name) {
this.rootClass = name;
}
+ /**
+ * Get the name of the root class
+ *
+ * @return the name of the root class.
+ */
public String getClassname() {
return rootClass;
}
}
+ /**
+ * Default constructor
+ */
+ public ClassfileSet() {
+ }
+
+ /**
+ * Create a ClassfileSet from another ClassfileSet
+ *
+ * @param s the other classfileset
+ */
protected ClassfileSet(ClassfileSet s) {
super(s);
- rootClasses = s.rootClasses;
+ rootClasses = (Vector)s.rootClasses.clone();
}
- public void setRootClass(String rootClass)
- throws BuildException
- {
- rootClasses.add(rootClass);
+ /**
+ * Set the root class attribute
+ *
+ * @param rootClass the name of the root class.
+ */
+ public void setRootClass(String rootClass) {
+ rootClasses.addElement(rootClass);
}
/**
* Return the DirectoryScanner associated with this FileSet.
+ *
+ * @param p the project used to resolve dirs, etc.
+ *
+ * @return a dependency scanner.
*/
public DirectoryScanner getDirectoryScanner(Project p) {
DependScanner scanner = new DependScanner();
@@ -110,10 +145,20 @@ public class ClassfileSet extends FileSet {
return scanner;
}
+ /**
+ * Add a nested root class definition to this class file set
+ *
+ * @param root the configured class root.
+ */
public void addConfiguredRoot(ClassRoot root) {
rootClasses.add(root.getClassname());
}
+ /**
+ * Clone this data type.
+ *
+ * @return a clone of the class file set
+ */
public Object clone() {
if (isReference()) {
return new ClassfileSet((ClassfileSet) getRef(getProject()));
diff --git a/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java b/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java
index a3e82e75a..88c52bc41 100644
--- a/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java
+++ b/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java
@@ -54,43 +54,43 @@
package org.apache.tools.ant.types.optional.depend;
import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.Iterator;
-import java.util.HashSet;
-
-import org.apache.tools.ant.util.depend.Dependencies;
-import org.apache.tools.ant.util.depend.Filter;
+import java.util.Vector;
+import java.util.Enumeration;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
import org.apache.tools.ant.DirectoryScanner;
-
-import org.apache.bcel.classfile.JavaClass;
-import org.apache.bcel.classfile.ClassParser;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Path;
/**
* An interface used to describe the actions required by any type of
* directory scanner.
+ *
+ * @author Conor MacNeill
+ * @author Holger Engels
*/
public class DependScanner extends DirectoryScanner {
- File basedir;
- File baseClass;
- List included = new LinkedList();
+ /**
+ * The name of the analyzer to use by default.
+ */
+ public static final String DEFAULT_ANALYZER_CLASS
+ = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
- private List rootClasses;
+ /**
+ * The base directory for the scan
+ */
+ private File basedir;
/**
- * Sets the basedir for scanning. This is the directory that is scanned
- * recursively.
- *
- * @param basedir the (non-null) basedir for scanning
+ * The root classes to drive the search for dependent classes
*/
- public void setBasedir(String basedir) {
- setBasedir(new File(basedir.replace('/',File.separatorChar).replace('\\',File.separatorChar)));
- }
-
+ private Vector rootClasses;
+
+ /**
+ * The names of the classes to include in the fileset
+ */
+ private Vector included;
+
/**
* Sets the basedir for scanning. This is the directory that is scanned
* recursively.
@@ -100,6 +100,7 @@ public class DependScanner extends DirectoryScanner {
public void setBasedir(File basedir) {
this.basedir = basedir;
}
+
/**
* Gets the basedir that is used for scanning.
*
@@ -108,11 +109,11 @@ public class DependScanner extends DirectoryScanner {
public File getBasedir() { return basedir; }
/**
- * Sets the domain, where dependant classes are searched
+ * Sets the root classes to be used to drive the scan.
*
- * @param domain the domain
+ * @param rootClasses the rootClasses to be used for this scan
*/
- public void setRootClasses(List rootClasses) {
+ public void setRootClasses(Vector rootClasses) {
this.rootClasses = rootClasses;
}
@@ -125,7 +126,11 @@ public class DependScanner extends DirectoryScanner {
int count = included.size();
String[] files = new String[count];
for (int i = 0; i < count; i++) {
- files[i] = included.get(i) + ".class";
+ String classname = (String)included.elementAt(i);
+ String filename = classname.replace('.', File.separatorChar);
+ filename = filename + ".class";
+ File file = new File(basedir, filename);
+ files[i] = file.getPath();
//System.err.println(" " + files[i]);
}
return files;
@@ -136,68 +141,86 @@ public class DependScanner extends DirectoryScanner {
*
* @exception IllegalStateException when basedir was set incorrecly
*/
- public void scan() {
- Dependencies visitor = new Dependencies();
-
- Set set = new TreeSet();
-
- final String base;
+ public void scan() throws IllegalStateException {
+ String analyzerClassName = DEFAULT_ANALYZER_CLASS;
+ DependencyAnalyzer analyzer = null;
try {
- base = basedir.getCanonicalPath() + File.separator;
+ Class analyzerClass = Class.forName(analyzerClassName);
+ analyzer = (DependencyAnalyzer)analyzerClass.newInstance();
+ } catch (Exception e) {
+ throw new BuildException("Unable to load dependency analyzer: "
+ + analyzerClassName, e);
}
- catch (Exception e) {
- throw new IllegalArgumentException(e.getMessage());
+ analyzer.addClassPath(new Path(null, basedir.getPath()));
+
+ for (Enumeration e = rootClasses.elements(); e.hasMoreElements(); ) {
+ analyzer.addRootClass((String)e.nextElement());
}
- for (Iterator rootClassIterator = rootClasses.iterator(); rootClassIterator.hasNext();) {
- Set newSet = new HashSet();
- String start = (String)rootClassIterator.next();
- start = start.replace('.', '/');
+ Enumeration e = analyzer.getClassDependencies();
- newSet.add(start);
- set.add(start);
-
- do {
- Iterator i = newSet.iterator();
- while (i.hasNext()) {
- String fileName = base + ((String)i.next()).replace('/', File.separatorChar) + ".class";
-
- try {
- JavaClass javaClass = new ClassParser(fileName).parse();
- javaClass.accept(visitor);
- }
- catch (IOException e) {
- System.err.println("exception: " + e.getMessage());
- }
- }
- newSet.clear();
- newSet.addAll(visitor.getDependencies());
- visitor.clearDependencies();
-
- Dependencies.applyFilter(newSet, new Filter() {
- public boolean accept(Object object) {
- String fileName = base + ((String)object).replace('/', File.separatorChar) + ".class";
- return new File(fileName).exists();
- }
- });
- newSet.removeAll(set);
- set.addAll(newSet);
- }
- while (newSet.size() > 0);
+ included.removeAllElements();
+ while (e.hasMoreElements()) {
+ included.addElement(e.nextElement());
}
-
- included.clear();
- included.addAll(set);
}
- public void addDefaultExcludes() {}
- public String[] getExcludedDirectories() { return null; }
- public String[] getExcludedFiles() { return null; }
- public String[] getIncludedDirectories() { return new String[0]; }
- public String[] getNotIncludedDirectories() { return null; }
- public String[] getNotIncludedFiles() { return null; }
+ /**
+ * @see DirectoryScanner#addDefaultExcludes
+ */
+ public void addDefaultExcludes() {
+ }
+
+ /**
+ * @see DirectoryScanner#getExcludedDirectories
+ */
+ public String[] getExcludedDirectories() {
+ return null;
+ }
+
+ /**
+ * @see DirectoryScanner#getExcludedFiles
+ */
+ public String[] getExcludedFiles() {
+ return null;
+ }
+
+ /**
+ * @see DirectoryScanner#getIncludedDirectories
+ */
+ public String[] getIncludedDirectories() {
+ return new String[0];
+ }
+
+ /**
+ * @see DirectoryScanner#getNotIncludedDirectories
+ */
+ public String[] getNotIncludedDirectories() {
+ return null;
+ }
+
+ /**
+ * @see DirectoryScanner#getNotIncludedFiles
+ */
+ public String[] getNotIncludedFiles() {
+ return null;
+ }
- public void setExcludes(String[] excludes) {}
- public void setIncludes(String[] includes) {}
- public void setCaseSensitive(boolean isCaseSensitive) {}
+ /**
+ * @see DirectoryScanner#setExcludes
+ */
+ public void setExcludes(String[] excludes) {
+ }
+
+ /**
+ * @see DirectoryScanner#setIncludes
+ */
+ public void setIncludes(String[] includes) {
+ }
+
+ /**
+ * @see DirectoryScanner#setCaseSensitive
+ */
+ public void setCaseSensitive(boolean isCaseSensitive) {
+ }
}
diff --git a/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java b/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
new file mode 100644
index 000000000..e6510d082
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
@@ -0,0 +1,324 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 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 "The Jakarta Project", "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
+ * .
+ */
+package org.apache.tools.ant.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.ZipFile;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * An abstract implementation of the analyzer interface providing support
+ * for the bulk of interface methods.
+ *
+ * @author Conor MacNeill
+ * @created 13 March 2002
+ */
+public abstract class AbstractAnalyzer implements DependencyAnalyzer {
+ /** Maximum number of loops for looking for indirect dependencies. */
+ public static final int MAX_LOOPS = 1000;
+
+ /** The source path for the source files */
+ private Path sourcePath = new Path(null);
+
+ /** The classpath containg dirs and jars of class files */
+ private Path classPath = new Path(null);
+
+ /** The list of root classes */
+ private Vector rootClasses = new Vector();
+
+ /** true if dependencies have been determined */
+ private boolean determined = false;
+
+ /** the list of File objects that the root classes depend upon */
+ private Vector fileDependencies;
+ /** the list of java classes the root classes depend upon */
+ private Vector classDependencies;
+
+ /** true if indirect dependencies should be gathered */
+ private boolean closure = true;
+
+ /** Setup the analyzer */
+ protected AbstractAnalyzer() {
+ reset();
+ }
+
+ /**
+ * Set the closure flag. If this flag is true the analyzer will traverse
+ * all class relationships until it has collected the entire set of
+ * direct and indirect dependencies
+ *
+ * @param closure true if dependencies should be traversed to determine
+ * indirect dependencies.
+ */
+ public void setClosure(boolean closure) {
+ this.closure = closure;
+ }
+
+ /**
+ * Get the list of files in the file system upon which the root classes
+ * depend. The files will be either the classfiles or jar files upon
+ * which the root classes depend.
+ *
+ * @return an enumeration of File instances.
+ * @exception UnsupportedOperationException if the analyzer cannot
+ * determine file dependencies.
+ */
+ public Enumeration getFileDependencies()
+ throws UnsupportedOperationException {
+ if (!supportsFileDependencies()) {
+ throw new UnsupportedOperationException();
+ }
+ if (!determined) {
+ determineDependencies(fileDependencies, classDependencies);
+ }
+ return fileDependencies.elements();
+ }
+
+ /**
+ * Get the list of classes upon which root classes depend. This is a
+ * list of Java classnames in dot notation.
+ *
+ * @return an enumeration of Strings, each being the name of a Java
+ * class in dot notation.
+ */
+ public Enumeration getClassDependencies() {
+ if (!determined) {
+ determineDependencies(fileDependencies, classDependencies);
+ }
+ return classDependencies.elements();
+ }
+
+ /**
+ * Get the file that contains the class definition
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the classpath cannot be read.
+ */
+ public File getClassContainer(String classname) throws IOException {
+ String classLocation = classname.replace('.', '/') + ".class";
+ // we look through the classpath elements. If the element is a dir
+ // we look for the file. IF it is a zip, we look for the zip entry
+ return getResourceContainer(classLocation, classPath.list());
+ }
+
+ /**
+ * Get the file that contains the class source.
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or java, containing the
+ * source or null if the source for the class could not be found.
+ * @exception IOException if the files in the sourcepath cannot be read.
+ */
+ public File getSourceContainer(String classname) throws IOException {
+ String sourceLocation = classname.replace('.', '/') + ".java";
+
+ // we look through the source path elements. If the element is a dir
+ // we look for the file. If it is a zip, we look for the zip entry.
+ // This isn't normal for source paths but we get it for free
+ return getResourceContainer(sourceLocation, sourcePath.list());
+ }
+
+ /**
+ * Add a source path to the source path used by this analyzer. The
+ * elements in the given path contain the source files for the classes
+ * being analyzed. Not all analyzers will use this information.
+ *
+ * @param sourcePath The Path instance specifying the source path
+ * elements.
+ */
+ public void addSourcePath(Path sourcePath) {
+ if (sourcePath == null) {
+ return;
+ }
+ this.sourcePath.append(sourcePath);
+ this.sourcePath.setProject(sourcePath.getProject());
+ }
+
+ /**
+ * Add a classpath to the classpath being used by the analyzer. The
+ * classpath contains the binary classfiles for the classes being
+ * analyzed The elements may either be the directories or jar files.Not
+ * all analyzers will use this information.
+ *
+ * @param classPath the Path instance specifying the classpath elements
+ */
+ public void addClassPath(Path classPath) {
+ if (classPath == null) {
+ return;
+ }
+
+ this.classPath.append(classPath);
+ this.classPath.setProject(classPath.getProject());
+ }
+
+ /**
+ * Add a root class. The root classes are used to drive the
+ * determination of dependency information. The analyzer will start at
+ * the root classes and add dependencies from there.
+ *
+ * @param className the name of the class in Java dot notation.
+ */
+ public void addRootClass(String className) {
+ if (className == null) {
+ return;
+ }
+ if (!rootClasses.contains(className)) {
+ rootClasses.addElement(className);
+ }
+ }
+
+ /**
+ * Configure an aspect of the analyzer. The set of aspects that are
+ * supported is specific to each analyzer instance.
+ *
+ * @param name the name of the aspect being configured
+ * @param info the configuration info.
+ */
+ public void config(String name, Object info) {
+ // do nothing by default
+ }
+
+ /**
+ * Reset the dependency list. This will reset the determined
+ * dependencies and the also list of root classes.
+ */
+ public void reset() {
+ rootClasses.clear();
+ determined = false;
+ fileDependencies = new Vector();
+ classDependencies = new Vector();
+ }
+
+ /**
+ * Get an enumeration of the root classes
+ *
+ * @return an enumeration of Strings, each of which is a class name
+ * for a root class.
+ */
+ protected Enumeration getRootClasses() {
+ return rootClasses.elements();
+ }
+
+ /**
+ * Indicate if the analyzer is required to follow
+ * indirect class relationships.
+ *
+ * @return true if indirect relationships should be followed.
+ */
+ protected boolean isClosureRequired() {
+ return closure;
+ }
+
+ /**
+ * Determine the dependencies of the current set of root classes
+ *
+ * @param files a vector into which Files upon which the root classes
+ * depend should be placed.
+ * @param classes a vector of Strings into which the names of classes
+ * upon which the root classes depend should be placed.
+ */
+ protected abstract void determineDependencies(Vector files, Vector classes);
+
+ /**
+ * Indicate if the particular subclass supports file dependency
+ * information.
+ *
+ * @return true if file dependencies are supported.
+ */
+ protected abstract boolean supportsFileDependencies();
+
+ /**
+ * Get the file that contains the resource
+ *
+ * @param resourceLocation the name of the required resource.
+ * @param paths the paths which will be searched for the resource.
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the given paths cannot be read.
+ */
+ private File getResourceContainer(String resourceLocation, String[] paths)
+ throws IOException {
+ for (int i = 0; i < paths.length; ++i) {
+ File element = new File(paths[i]);
+ if (!element.exists()) {
+ continue;
+ }
+ if (element.isDirectory()) {
+ File resource = new File(element, resourceLocation);
+ if (resource.exists()) {
+ return resource;
+ }
+ } else {
+ // must be a zip of some sort
+ ZipFile zipFile = null;
+ try {
+ zipFile = new ZipFile(element);
+ if (zipFile.getEntry(resourceLocation) != null) {
+ return element;
+ }
+ } finally {
+ if (zipFile != null) {
+ zipFile.close();
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/src/main/org/apache/tools/ant/util/depend/Dependencies.java b/src/main/org/apache/tools/ant/util/depend/Dependencies.java
deleted file mode 100644
index 277cfedb4..000000000
--- a/src/main/org/apache/tools/ant/util/depend/Dependencies.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2001-2002 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 "The Jakarta Project", "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
- * .
- */
-package org.apache.tools.ant.util.depend;
-
-import java.io.File;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.StringTokenizer;
-import java.util.TreeSet;
-import java.util.Iterator;
-import java.util.Collection;
-import org.apache.bcel.classfile.EmptyVisitor;
-import org.apache.bcel.classfile.JavaClass;
-import org.apache.bcel.classfile.ConstantPool;
-import org.apache.bcel.classfile.Code;
-import org.apache.bcel.classfile.CodeException;
-import org.apache.bcel.classfile.ConstantClass;
-import org.apache.bcel.classfile.ConstantDouble;
-import org.apache.bcel.classfile.ConstantFieldref;
-import org.apache.bcel.classfile.ConstantFloat;
-import org.apache.bcel.classfile.ConstantInteger;
-import org.apache.bcel.classfile.ConstantInterfaceMethodref;
-import org.apache.bcel.classfile.ConstantLong;
-import org.apache.bcel.classfile.ConstantMethodref;
-import org.apache.bcel.classfile.ConstantNameAndType;
-import org.apache.bcel.classfile.Constant;
-import org.apache.bcel.classfile.ConstantString;
-import org.apache.bcel.classfile.ConstantUtf8;
-import org.apache.bcel.classfile.ConstantValue;
-import org.apache.bcel.classfile.Deprecated;
-import org.apache.bcel.classfile.ExceptionTable;
-import org.apache.bcel.classfile.Field;
-import org.apache.bcel.classfile.InnerClass;
-import org.apache.bcel.classfile.InnerClasses;
-import org.apache.bcel.classfile.Method;
-import org.apache.bcel.classfile.LineNumber;
-import org.apache.bcel.classfile.LineNumberTable;
-import org.apache.bcel.classfile.LocalVariable;
-import org.apache.bcel.classfile.LocalVariableTable;
-import org.apache.bcel.classfile.SourceFile;
-import org.apache.bcel.classfile.Synthetic;
-import org.apache.bcel.classfile.Unknown;
-import org.apache.bcel.classfile.StackMap;
-import org.apache.bcel.classfile.StackMapEntry;
-import org.apache.bcel.classfile.ClassParser;
-
-
-
-public class Dependencies extends EmptyVisitor {
- private boolean verbose = false;
-
- private JavaClass javaClass;
- private ConstantPool constantPool;
- private Set dependencies = new HashSet();
-
- public void clearDependencies() {
- dependencies.clear();
- }
-
- public Set getDependencies() {
- return dependencies;
- }
-
- public void visitConstantClass(ConstantClass obj) {
- if (verbose) {
- System.out.println("visit ConstantClass");
- System.out.println(obj.getConstantValue(constantPool));
- }
- dependencies.add("" + obj.getConstantValue(constantPool));
- }
-
- public void visitConstantPool(ConstantPool obj) {
- if (verbose) {
- System.out.println("visit ConstantPool");
- }
- this.constantPool = obj;
-
- // visit constants
- for(int idx = 0; idx < constantPool.getLength(); idx++) {
- Constant c = constantPool.getConstant(idx);
- if (c != null) {
- c.accept(this);
- }
- }
- }
-
- public void visitField(Field obj) {
- if (verbose) {
- System.out.println("visit Field");
- System.out.println(obj.getSignature());
- }
- addClasses(obj.getSignature());
- }
-
- public void visitJavaClass(JavaClass obj) {
- if (verbose) {
- System.out.println("visit JavaClass");
- }
-
- this.javaClass = obj;
- dependencies.add(javaClass.getClassName().replace('.', '/'));
-
- // visit constant pool
- javaClass.getConstantPool().accept(this);
-
- // visit fields
- Field[] fields = obj.getFields();
- for(int i=0; i < fields.length; i++) {
- fields[i].accept(this);
- }
-
- // visit methods
- Method[] methods = obj.getMethods();
- for(int i=0; i < methods.length; i++) {
- methods[i].accept(this);
- }
- }
-
- public void visitMethod(Method obj) {
- if (verbose) {
- System.out.println("visit Method");
- System.out.println(obj.getSignature());
- }
- String signature = obj.getSignature();
- int pos = signature.indexOf(")");
- addClasses(signature.substring(1, pos));
- addClasses(signature.substring(pos + 1));
- }
-
- void addClasses(String string) {
- StringTokenizer tokens = new StringTokenizer(string, ";");
- while (tokens.hasMoreTokens()) {
- addClass(tokens.nextToken());
- }
- }
-
- void addClass(String string) {
- int pos = string.indexOf('L');
- if (pos != -1) {
- dependencies.add(string.substring(pos+1));
- }
- }
-
- public static void main(String[] args) {
- try {
- Dependencies visitor = new Dependencies();
-
- Set set = new TreeSet();
- Set newSet = new HashSet();
-
- int o=0;
- String arg = null;
- if ("-base".equals(args[0])) {
- arg = args[1];
- if (!arg.endsWith(File.separator)) {
- arg = arg + File.separator;
- }
- o=2;
- }
- final String base = arg;
-
- for (int i=o; i < args.length; i++) {
- String fileName = args[i].substring(0, args[i].length() - ".class".length());
- if (base != null && fileName.startsWith(base)) {
- fileName = fileName.substring(base.length());
- }
- newSet.add(fileName);
- }
- set.addAll(newSet);
-
- do {
- Iterator i = newSet.iterator();
- while (i.hasNext()) {
- String fileName = i.next() + ".class";
-
- if (base != null) {
- fileName = base + fileName;
- }
-
- JavaClass javaClass = new ClassParser(fileName).parse();
- javaClass.accept(visitor);
- }
- newSet.clear();
- newSet.addAll(visitor.getDependencies());
- visitor.clearDependencies();
-
- applyFilter(newSet, new Filter() {
- public boolean accept(Object object) {
- String fileName = object + ".class";
- if (base != null) {
- fileName = base + fileName;
- }
- return new File(fileName).exists();
- }
- });
- newSet.removeAll(set);
- set.addAll(newSet);
- }
- while (newSet.size() > 0);
-
- Iterator i = set.iterator();
- while (i.hasNext()) {
- System.out.println(i.next());
- }
- }
- catch (Exception e) {
- System.err.println(e.getMessage());
- e.printStackTrace(System.err);
- }
- }
-
- public static void applyFilter(Collection collection, Filter filter) {
- Iterator i = collection.iterator();
- while (i.hasNext()) {
- Object next = i.next();
- if (!filter.accept(next)) {
- i.remove();
- }
- }
- }
-}
diff --git a/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java b/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
new file mode 100644
index 000000000..c6940b774
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
@@ -0,0 +1,170 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 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 "The Jakarta Project", "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
+ * .
+ */
+package org.apache.tools.ant.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.types.Path;
+
+/**
+ * A dependency analyzer analyzes dependencies between Java classes to
+ * determine the minimal set of classes which are required by a set of
+ * "root" classes. Different implementations of this interface can
+ * use different strategies and libraries to determine the required set. For
+ * example, some analyzers will use class files while others might use
+ * source files. Analyzer specific configuration is catered for through a
+ * generic configure method
+ *
+ * @author Conor MacNeill
+ * @created 13 March 2002
+ */
+public interface DependencyAnalyzer {
+ /**
+ * Add a source path to the source path used by this analyzer. The
+ * elements in the given path contain the source files for the classes
+ * being analyzed. Not all analyzers will use this information.
+ *
+ * @param sourcePath The Path instance specifying the source path
+ * elements.
+ */
+ void addSourcePath(Path sourcePath);
+
+ /**
+ * Add a classpath to the classpath being used by the analyzer. The
+ * classpath contains the binary classfiles for the classes being
+ * analyzed The elements may either be the directories or jar files.Not
+ * all analyzers will use this information.
+ *
+ * @param classpath the Path instance specifying the classpath elements
+ */
+ void addClassPath(Path classpath);
+
+ /**
+ * Add a root class. The root classes are used to drive the
+ * determination of dependency information. The analyzer will start at
+ * the root classes and add dependencies from there.
+ *
+ * @param classname the name of the class in Java dot notation.
+ */
+ void addRootClass(String classname);
+
+ /**
+ * Get the list of files in the file system upon which the root classes
+ * depend. The files will be either the classfiles or jar files upon
+ * which the root classes depend.
+ *
+ * @return an enumeration of File instances.
+ * @exception UnsupportedOperationException if the analyzer cannot
+ * determine file dependencies.
+ */
+ Enumeration getFileDependencies() throws UnsupportedOperationException;
+
+ /**
+ * Get the list of classes upon which root classes depend. This is a
+ * list of Java classnames in dot notation.
+ *
+ * @return an enumeration of Strings, each being the name of a Java
+ * class in dot notation.
+ */
+ Enumeration getClassDependencies();
+
+
+ /**
+ * Reset the dependency list. This will reset the determined
+ * dependencies and the also list of root classes.
+ */
+ void reset();
+
+ /**
+ * Configure an aspect of the analyzer. The set of aspects that are
+ * supported is specific to each analyzer instance.
+ *
+ * @param name the name of the aspect being configured
+ * @param info the configuration information.
+ */
+ void config(String name, Object info);
+
+ /**
+ * Set the closure flag. If this flag is true the analyzer will traverse
+ * all class relationships until it has collected the entire set of
+ * direct and indirect dependencies
+ *
+ * @param closure true if dependencies should be traversed to determine
+ * indirect dependencies.
+ */
+ void setClosure(boolean closure);
+
+
+ /**
+ * Get the file that contains the class definition
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the classpath cannot be read.
+ */
+ File getClassContainer(String classname) throws IOException;
+
+ /**
+ * Get the file that contains the class source.
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or java, containing the
+ * source or null if the source for the class could not be found.
+ * @exception IOException if the files in the sourcepath cannot be read.
+ */
+ File getSourceContainer(String classname) throws IOException;
+}
+
diff --git a/src/main/org/apache/tools/ant/util/depend/Filter.java b/src/main/org/apache/tools/ant/util/depend/Filter.java
deleted file mode 100644
index ace12fbcb..000000000
--- a/src/main/org/apache/tools/ant/util/depend/Filter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2001 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 "The Jakarta Project", "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
- * .
- */
-package org.apache.tools.ant.util.depend;
-
-
-
-public interface Filter {
- boolean accept(Object object);
-}
diff --git a/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java b/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
new file mode 100644
index 000000000..5ed8ac156
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
@@ -0,0 +1,160 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 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 "The Jakarta Project", "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
+ * .
+ */
+package org.apache.tools.ant.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * A dependency analyzer which returns superclass and superinterface
+ * dependencies.
+ *
+ * @author Conor MacNeill
+ * @created 13 March 2002
+ */
+public class AncestorAnalyzer extends AbstractAnalyzer {
+ /**
+ * Determine the dependencies of the configured root classes.
+ *
+ * @param files a vector to be populated with the files which contain
+ * the dependency classes
+ * @param classes a vector to be populated with the names of the
+ * depencency classes.
+ */
+ protected void determineDependencies(Vector files, Vector classes) {
+ // we get the root classes and build up a set of
+ // classes upon which they depend
+ Hashtable dependencies = new Hashtable();
+ Hashtable containers = new Hashtable();
+ Hashtable toAnalyze = new Hashtable();
+ Hashtable nextAnalyze = new Hashtable();
+ for (Enumeration e = getRootClasses(); e.hasMoreElements(); ) {
+ String classname = (String)e.nextElement();
+ toAnalyze.put(classname, classname);
+ }
+
+ int count = 0;
+ int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+ while (toAnalyze.size() != 0 && count++ < maxCount) {
+ nextAnalyze.clear();
+ for (Enumeration e = toAnalyze.keys(); e.hasMoreElements(); ) {
+ String classname = (String)e.nextElement();
+ dependencies.put(classname, classname);
+ try {
+ File container = getClassContainer(classname);
+ if (container == null) {
+ continue;
+ }
+ containers.put(container, container);
+
+ ClassParser parser = null;
+ if (container.getName().endsWith(".class")) {
+ parser = new ClassParser(container.getPath());
+ } else {
+ parser = new ClassParser(container.getPath(),
+ classname.replace('.', '/') + ".class");
+ }
+
+ JavaClass javaClass = parser.parse();
+ String[] interfaces = javaClass.getInterfaceNames();
+ for (int i = 0; i < interfaces.length; ++i) {
+ String interfaceName = interfaces[i];
+ if (!dependencies.containsKey(interfaceName)) {
+ nextAnalyze.put(interfaceName, interfaceName);
+ }
+ }
+
+ if (javaClass.isClass()) {
+ String superClass = javaClass.getSuperclassName();
+ if (!dependencies.containsKey(superClass)) {
+ nextAnalyze.put(superClass, superClass);
+ }
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ Hashtable temp = toAnalyze;
+ toAnalyze = nextAnalyze;
+ nextAnalyze = temp;
+ }
+
+ files.removeAllElements();
+ for (Enumeration e = containers.keys(); e.hasMoreElements(); ) {
+ files.addElement((File)e.nextElement());
+ }
+
+ classes.removeAllElements();
+ for (Enumeration e = dependencies.keys(); e.hasMoreElements(); ) {
+ classes.addElement((String)e.nextElement());
+ }
+ }
+
+ /**
+ * Indicate if this analyzer can determine dependent files.
+ *
+ * @return true if the analyzer provides dependency file information.
+ */
+ protected boolean supportsFileDependencies() {
+ return true;
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java b/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
new file mode 100644
index 000000000..984d221bf
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
@@ -0,0 +1,182 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001-2002 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 "The Jakarta Project", "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
+ * .
+ */
+package org.apache.tools.ant.util.depend.bcel;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import org.apache.bcel.classfile.ConstantClass;
+import org.apache.bcel.classfile.ConstantPool;
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+
+/**
+ * A BCEL visitor implementation to collect class dependency information
+ *
+ * @author Conor MacNeill
+ * @author Holger Engels
+ * @created 15 March 2002
+ */
+public class DependencyVisitor extends EmptyVisitor {
+ /** The collectd dependencies */
+ private Hashtable dependencies = new Hashtable();
+ /**
+ * The current class's constant pool - used to determine class names
+ * from class references.
+ */
+ private ConstantPool constantPool;
+
+ /**
+ * Get the dependencies collected by this visitor
+ *
+ * @return a Enumeration of classnames, being the classes upon which the
+ * visited classes depend.
+ */
+ public Enumeration getDependencies() {
+ return dependencies.keys();
+ }
+
+ /** Clear the curretn set of collected dependencies. */
+ public void clearDependencies() {
+ dependencies.clear();
+ }
+
+ /**
+ * Visit the constant pool of a class
+ *
+ * @param constantPool the constant pool of the class being visited.
+ */
+ public void visitConstantPool(ConstantPool constantPool) {
+ this.constantPool = constantPool;
+ }
+
+ /**
+ * Visit a class reference
+ *
+ * @param constantClass the constantClass entry for the class reference
+ */
+ public void visitConstantClass(ConstantClass constantClass) {
+ String classname
+ = constantClass.getConstantValue(constantPool).toString();
+ addSlashClass(classname);
+ }
+
+ /**
+ * Visit a field of the class.
+ *
+ * @param field the field being visited
+ */
+ public void visitField(Field field) {
+ addClasses(field.getSignature());
+ }
+
+ /**
+ * Visit a Java class
+ *
+ * @param javaClass the class being visited.
+ */
+ public void visitJavaClass(JavaClass javaClass) {
+ addClass(javaClass.getClassName());
+ }
+
+ /**
+ * Visit a method of the current class
+ *
+ * @param method the method being visited.
+ */
+ public void visitMethod(Method method) {
+ String signature = method.getSignature();
+ int pos = signature.indexOf(")");
+ addClasses(signature.substring(1, pos));
+ addClasses(signature.substring(pos + 1));
+ }
+
+ /**
+ * Add a classname to the list of dependency classes
+ *
+ * @param classname the class to be added to the list of dependencies.
+ */
+ void addClass(String classname) {
+ dependencies.put(classname, classname);
+ }
+
+ /**
+ * Add all the classes from a descriptor string.
+ *
+ * @param string the descriptor string, being descriptors separated by
+ * ';' characters.
+ */
+ private void addClasses(String string) {
+ StringTokenizer tokens = new StringTokenizer(string, ";");
+ while (tokens.hasMoreTokens()) {
+ String descriptor = tokens.nextToken();
+ int pos = descriptor.indexOf('L');
+ if (pos != -1) {
+ addSlashClass(descriptor.substring(pos + 1));
+ }
+ }
+ }
+
+ /**
+ * Add a class name in slash format (e.g. org/apache/tools/ant/...)
+ *
+ * @param classname the class name in slash format
+ */
+ private void addSlashClass(String classname) {
+ addClass(classname.replace('/', '.'));
+ }
+}
+
diff --git a/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java b/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
new file mode 100644
index 000000000..f8041d4da
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
@@ -0,0 +1,156 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 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 "The Jakarta Project", "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
+ * .
+ */
+package org.apache.tools.ant.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.DescendingVisitor;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * An analyzer capable fo traversing all class - class relationships.
+ *
+ * @author Conor MacNeill
+ * @author Holger Engels
+ * @created 13 March 2002
+ */
+public class FullAnalyzer extends AbstractAnalyzer {
+ /**
+ * Determine the dependencies of the configured root classes.
+ *
+ * @param files a vector to be populated with the files which contain
+ * the dependency classes
+ * @param classes a vector to be populated with the names of the
+ * depencency classes.
+ */
+ protected void determineDependencies(Vector files, Vector classes) {
+ // we get the root classes and build up a set of
+ // classes upon which they depend
+ Hashtable dependencies = new Hashtable();
+ Hashtable containers = new Hashtable();
+ Hashtable toAnalyze = new Hashtable();
+ for (Enumeration e = getRootClasses(); e.hasMoreElements(); ) {
+ String classname = (String)e.nextElement();
+ toAnalyze.put(classname, classname);
+ }
+
+ int count = 0;
+ int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+ while (toAnalyze.size() != 0 && count++ < maxCount) {
+ DependencyVisitor dependencyVisitor = new DependencyVisitor();
+ for (Enumeration e = toAnalyze.keys(); e.hasMoreElements(); ) {
+ String classname = (String)e.nextElement();
+ dependencies.put(classname, classname);
+ try {
+ File container = getClassContainer(classname);
+ if (container == null) {
+ continue;
+ }
+ containers.put(container, container);
+
+ ClassParser parser = null;
+ if (container.getName().endsWith(".class")) {
+ parser = new ClassParser(container.getPath());
+ } else {
+ parser = new ClassParser(container.getPath(),
+ classname.replace('.', '/') + ".class");
+ }
+
+ JavaClass javaClass = parser.parse();
+ DescendingVisitor traverser
+ = new DescendingVisitor(javaClass, dependencyVisitor);
+ traverser.visit();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ toAnalyze.clear();
+
+ // now recover all the dependencies collected and add to the list.
+ Enumeration depsEnum = dependencyVisitor.getDependencies();
+ while (depsEnum.hasMoreElements()) {
+ String className = (String)depsEnum.nextElement();
+ if (!dependencies.containsKey(className)) {
+ toAnalyze.put(className, className);
+ }
+ }
+ }
+
+ files.removeAllElements();
+ for (Enumeration e = containers.keys(); e.hasMoreElements(); ) {
+ files.addElement((File)e.nextElement());
+ }
+
+ classes.removeAllElements();
+ for (Enumeration e = dependencies.keys(); e.hasMoreElements(); ) {
+ classes.addElement((String)e.nextElement());
+ }
+ }
+
+ /**
+ * Indicate if this analyzer can determine dependent files.
+ *
+ * @return true if the analyzer provides dependency file information.
+ */
+ protected boolean supportsFileDependencies() {
+ return true;
+ }
+
+}
+