Add a DependencyAnalyzer interface Currently supports BCEL based analyzers Refactor ejbjar not to require BCEL to run. More to come ... git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271856 13f79535-47bb-0310-9956-ffa450edef68master
@@ -212,15 +212,7 @@ | |||||
<patternset id="needs.jakarta.bcel"> | <patternset id="needs.jakarta.bcel"> | ||||
<exclude name="${ant.package}/filters/util/JavaClassHelper.java" | <exclude name="${ant.package}/filters/util/JavaClassHelper.java" | ||||
unless="bcel.present" /> | unless="bcel.present" /> | ||||
<exclude name="${optional.type.package}/depend/*.java" | |||||
unless="bcel.present" /> | |||||
<exclude name="${util.package}/depend/*.java" | |||||
unless="bcel.present" /> | |||||
<exclude name="${optional.package}/ejb/EjbJar.java" | |||||
unless="bcel.present" /> | |||||
<exclude name="${optional.package}/ejb/*DeploymentTool.java" | |||||
unless="bcel.present" /> | |||||
<exclude name="${optional.package}/ejb/IPlanet*.java" | |||||
<exclude name="${util.package}/depend/bcel/*.java" | |||||
unless="bcel.present" /> | unless="bcel.present" /> | ||||
</patternset> | </patternset> | ||||
<patternset id="needs.jakarta.log4j"> | <patternset id="needs.jakarta.log4j"> | ||||
@@ -210,25 +210,25 @@ public class EjbJar extends MatchingTask { | |||||
* Naming scheme where generated jar is determined from the ejb-name in | * Naming scheme where generated jar is determined from the ejb-name in | ||||
* the deployment descripor | * 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 | * Naming scheme where the generated jar name is based on the | ||||
* name of the directory containing the deployment descriptor | * 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 | * Naming scheme where the generated jar name is based on the name of | ||||
* the deployment descriptor file | * 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 | * Naming scheme where the generated jar is named by the basejarname | ||||
* attribute | * attribute | ||||
*/ | */ | ||||
public final static String BASEJARNAME = "basejarname"; | |||||
public static final String BASEJARNAME = "basejarname"; | |||||
/** | /** | ||||
* Gets the values of the NamingScheme | * Gets the values of the NamingScheme | ||||
@@ -451,8 +451,7 @@ public class EjbJar extends MatchingTask { | |||||
if (config.namingScheme == null) { | if (config.namingScheme == null) { | ||||
config.namingScheme = new NamingScheme(); | config.namingScheme = new NamingScheme(); | ||||
config.namingScheme.setValue(NamingScheme.BASEJARNAME); | 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 " + | throw new BuildException("The basejarname attribute is not compatible with the " + | ||||
config.namingScheme.getValue() + " naming scheme"); | config.namingScheme.getValue() + " naming scheme"); | ||||
} | } | ||||
@@ -543,7 +542,7 @@ public class EjbJar extends MatchingTask { | |||||
* | * | ||||
* @throws BuildException if the config is not valid | * @throws BuildException if the config is not valid | ||||
*/ | */ | ||||
private void validateConfig() { | |||||
private void validateConfig() throws BuildException { | |||||
if (config.srcDir == null) { | if (config.srcDir == null) { | ||||
throw new BuildException("The srcDir attribute must be specified"); | throw new BuildException("The srcDir attribute must be specified"); | ||||
} | } | ||||
@@ -555,8 +554,7 @@ public class EjbJar extends MatchingTask { | |||||
if (config.namingScheme == null) { | if (config.namingScheme == null) { | ||||
config.namingScheme = new NamingScheme(); | config.namingScheme = new NamingScheme(); | ||||
config.namingScheme.setValue(NamingScheme.DESCRIPTOR); | config.namingScheme.setValue(NamingScheme.DESCRIPTOR); | ||||
} | |||||
else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME) && | |||||
} else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME) && | |||||
config.baseJarName == null) { | config.baseJarName == null) { | ||||
throw new BuildException("The basejarname attribute must be specified " + | throw new BuildException("The basejarname attribute must be specified " + | ||||
"with the basejarname naming scheme"); | "with the basejarname naming scheme"); | ||||
@@ -618,14 +616,12 @@ public class EjbJar extends MatchingTask { | |||||
tool.processDescriptor(files[index], saxParser); | tool.processDescriptor(files[index], saxParser); | ||||
} | } | ||||
} | } | ||||
} | |||||
catch (SAXException se) { | |||||
} catch (SAXException se) { | |||||
String msg = "SAXException while creating parser." | String msg = "SAXException while creating parser." | ||||
+ " Details: " | + " Details: " | ||||
+ se.getMessage(); | + se.getMessage(); | ||||
throw new BuildException(msg, se); | throw new BuildException(msg, se); | ||||
} | |||||
catch (ParserConfigurationException pce) { | |||||
} catch (ParserConfigurationException pce) { | |||||
String msg = "ParserConfigurationException while creating parser. " | String msg = "ParserConfigurationException while creating parser. " | ||||
+ "Details: " + pce.getMessage(); | + "Details: " + pce.getMessage(); | ||||
throw new BuildException(msg, pce); | throw new BuildException(msg, pce); | ||||
@@ -68,20 +68,17 @@ import java.util.ArrayList; | |||||
import java.util.jar.JarOutputStream; | import java.util.jar.JarOutputStream; | ||||
import java.util.jar.Manifest; | import java.util.jar.Manifest; | ||||
import java.util.zip.ZipEntry; | import java.util.zip.ZipEntry; | ||||
import java.util.Enumeration; | |||||
import javax.xml.parsers.SAXParser; | import javax.xml.parsers.SAXParser; | ||||
import org.xml.sax.InputSource; | import org.xml.sax.InputSource; | ||||
import org.xml.sax.SAXException; | 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.JavaClass; | ||||
import org.apache.bcel.classfile.ClassParser; | import org.apache.bcel.classfile.ClassParser; | ||||
import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.Location; | 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 | * 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 | * deployment tools. A number of template methods are provided through which the | ||||
* vendor specific tool can hook into the EJB creation process. | * vendor specific tool can hook into the EJB creation process. | ||||
* | |||||
* @author Conor MacNeill | |||||
*/ | */ | ||||
public class GenericDeploymentTool implements EJBDeploymentTool { | 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; | private EjbJar.Config config; | ||||
@@ -123,8 +127,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
private String genericJarSuffix = "-generic.jar"; | 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; | private Task task; | ||||
@@ -145,8 +149,25 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
private DescriptorHandler handler; | 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. | * @param inDir the destination directory. | ||||
*/ | */ | ||||
public void setDestdir(File inDir) { | public void setDestdir(File inDir) { | ||||
@@ -155,6 +176,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Get the desitination directory. | * Get the desitination directory. | ||||
* | |||||
* @return the destination directory into which EJB jars are to be written | |||||
*/ | */ | ||||
protected File getDestDir() { | protected File getDestDir() { | ||||
return destDir; | return destDir; | ||||
@@ -163,6 +186,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Set the task which owns this tool | * Set the task which owns this tool | ||||
* | |||||
* @param task the Task to which this deployment tool is associated. | |||||
*/ | */ | ||||
public void setTask(Task task) { | public void setTask(Task task) { | ||||
this.task = task; | this.task = task; | ||||
@@ -170,6 +195,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Get the task for this tool. | * Get the task for this tool. | ||||
* | |||||
* @return the Task instance this tool is associated with. | |||||
*/ | */ | ||||
protected Task getTask() { | protected Task getTask() { | ||||
return task; | return task; | ||||
@@ -177,13 +204,18 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Get the basename terminator. | * Get the basename terminator. | ||||
* | |||||
* @return an ejbjar task configuration | |||||
*/ | */ | ||||
protected EjbJar.Config getConfig() { | protected EjbJar.Config getConfig() { | ||||
return config; | 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() { | protected boolean usingBaseJarName() { | ||||
return config.baseJarName != null; | return config.baseJarName != null; | ||||
@@ -199,6 +231,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Add the classpath for the user classes | * Add the classpath for the user classes | ||||
* | |||||
* @return a Path instance to be configured by Ant. | |||||
*/ | */ | ||||
public Path createClasspath() { | public Path createClasspath() { | ||||
if (classpath == null) { | if (classpath == null) { | ||||
@@ -209,6 +243,8 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Set the classpath to be used for this compilation. | * Set the classpath to be used for this compilation. | ||||
* | |||||
* @param classpath the classpath to be used for this build. | |||||
*/ | */ | ||||
public void setClasspath(Path classpath) { | public void setClasspath(Path classpath) { | ||||
this.classpath = 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 | * Get the classpath by combining the one from the surrounding task, if any | ||||
* and the one from this tool. | * and the one from this tool. | ||||
* | |||||
* @return the combined classpath | |||||
*/ | */ | ||||
protected Path getCombinedClasspath() { | protected Path getCombinedClasspath() { | ||||
Path combinedPath = classpath; | Path combinedPath = classpath; | ||||
if (config.classpath != null) { | if (config.classpath != null) { | ||||
if (combinedPath == null) { | if (combinedPath == null) { | ||||
combinedPath = config.classpath; | combinedPath = config.classpath; | ||||
} | |||||
else { | |||||
} else { | |||||
combinedPath.append(config.classpath); | combinedPath.append(config.classpath); | ||||
} | } | ||||
} | } | ||||
@@ -232,10 +269,21 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
return combinedPath; | 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) { | protected void log(String message, int level) { | ||||
getTask().log(message, 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() { | protected Location getLocation() { | ||||
return getTask().getLocation(); | return getTask().getLocation(); | ||||
} | } | ||||
@@ -243,10 +291,15 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
/** | /** | ||||
* Configure this tool for use in the ejbjar task. | * Configure this tool for use in the ejbjar task. | ||||
* | |||||
* @param config the configuration from the surrounding ejbjar task. | |||||
*/ | */ | ||||
public void configure(EjbJar.Config config) { | public void configure(EjbJar.Config config) { | ||||
this.config = config; | this.config = config; | ||||
dependencyAnalyzer.addClassPath(new Path(task.getProject(), | |||||
config.srcDir.getPath())); | |||||
dependencyAnalyzer.addClassPath(config.classpath); | |||||
classpathLoader = null; | classpathLoader = null; | ||||
} | } | ||||
@@ -271,7 +324,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
if (!addedfiles.contains(logicalFilename)) { | if (!addedfiles.contains(logicalFilename)) { | ||||
iStream = new FileInputStream(inputFile); | iStream = new FileInputStream(inputFile); | ||||
// Create the zip entry and add it to the jar file | // 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); | jStream.putNextEntry(zipEntry); | ||||
// Create the file input stream, and buffer everything over | // 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 | //add it to list of files in jar | ||||
addedfiles.add(logicalFilename); | addedfiles.add(logicalFilename); | ||||
} | } | ||||
} | |||||
catch (IOException ioe) { | |||||
} catch (IOException ioe) { | |||||
log("WARNING: IOException while adding entry " + | log("WARNING: IOException while adding entry " + | ||||
logicalFilename + " to jarfile from " + inputFile.getPath() + " " + | logicalFilename + " to jarfile from " + inputFile.getPath() + " " + | ||||
ioe.getClass().getName() + "-" + ioe.getMessage(), Project.MSG_WARN); | ioe.getClass().getName() + "-" + ioe.getMessage(), Project.MSG_WARN); | ||||
} | |||||
finally { | |||||
} finally { | |||||
// Close up the file input stream for the class file | // Close up the file input stream for the class file | ||||
if (iStream != null) { | if (iStream != null) { | ||||
try { | try { | ||||
iStream.close(); | iStream.close(); | ||||
} | |||||
catch (IOException closeException) {} | |||||
} catch (IOException closeException) {} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -383,23 +433,20 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
String publicId = getPublicId(); | String publicId = getPublicId(); | ||||
writeJar(baseName, jarFile, ejbFiles, publicId); | writeJar(baseName, jarFile, ejbFiles, publicId); | ||||
} | |||||
else { | |||||
} else { | |||||
// Log that the file is up to date... | // Log that the file is up to date... | ||||
log(jarFile.toString() + " is up to date.", | log(jarFile.toString() + " is up to date.", | ||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
} | } | ||||
} | |||||
catch (SAXException se) { | |||||
} catch (SAXException se) { | |||||
String msg = "SAXException while parsing '" | String msg = "SAXException while parsing '" | ||||
+ descriptorFileName.toString() | + descriptorFileName.toString() | ||||
+ "'. This probably indicates badly-formed XML." | + "'. This probably indicates badly-formed XML." | ||||
+ " Details: " | + " Details: " | ||||
+ se.getMessage(); | + se.getMessage(); | ||||
throw new BuildException(msg, se); | throw new BuildException(msg, se); | ||||
} | |||||
catch (IOException ioe) { | |||||
} catch (IOException ioe) { | |||||
String msg = "IOException while parsing'" | String msg = "IOException while parsing'" | ||||
+ descriptorFileName.toString() | + descriptorFileName.toString() | ||||
+ "'. This probably indicates that the descriptor" | + "'. This probably indicates that the descriptor" | ||||
@@ -466,8 +513,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
if (descriptorStream != null) { | if (descriptorStream != null) { | ||||
try { | try { | ||||
descriptorStream.close(); | descriptorStream.close(); | ||||
} | |||||
catch (IOException closeException) {} | |||||
} catch (IOException closeException) {} | |||||
} | } | ||||
} | } | ||||
@@ -566,8 +612,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
int index = canonicalDescriptor.lastIndexOf('/'); | int index = canonicalDescriptor.lastIndexOf('/'); | ||||
if (index == -1) { | if (index == -1) { | ||||
ddPrefix = ""; | ddPrefix = ""; | ||||
} | |||||
else { | |||||
} else { | |||||
ddPrefix = descriptorFileName.substring(0, index + 1); | 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 | // Loop through the files seeing if any has been touched | ||||
// more recently than the destination jar. | // more recently than the destination jar. | ||||
while(fileIter.hasNext()) { | |||||
while (fileIter.hasNext()) { | |||||
File currentFile = (File) fileIter.next(); | File currentFile = (File) fileIter.next(); | ||||
if (lastBuild < currentFile.lastModified()) { | if (lastBuild < currentFile.lastModified()) { | ||||
log("Build needed because " + currentFile.getPath() + " is out of date", | log("Build needed because " + currentFile.getPath() + " is out of date", | ||||
@@ -641,7 +686,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
* every vendor-specific <code>DeploymentTool</code> will need to reference | * every vendor-specific <code>DeploymentTool</code> will need to reference | ||||
* this value or may want to determine this value in a vendor-specific way. | * 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() { | protected String getPublicId() { | ||||
return handler.getPublicId(); | return handler.getPublicId(); | ||||
@@ -677,15 +722,13 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
File manifestFile = new File(getConfig().descriptorDir, baseName + "-manifest.mf"); | File manifestFile = new File(getConfig().descriptorDir, baseName + "-manifest.mf"); | ||||
if (manifestFile.exists()) { | if (manifestFile.exists()) { | ||||
in = new FileInputStream(manifestFile); | in = new FileInputStream(manifestFile); | ||||
} | |||||
else if (config.manifest != null) { | |||||
} else if (config.manifest != null) { | |||||
in = new FileInputStream(config.manifest); | in = new FileInputStream(config.manifest); | ||||
if ( in == null ) { | if ( in == null ) { | ||||
throw new BuildException("Could not find manifest file: " + config.manifest, | throw new BuildException("Could not find manifest file: " + config.manifest, | ||||
getLocation()); | getLocation()); | ||||
} | } | ||||
} | |||||
else { | |||||
} else { | |||||
String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf"; | String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf"; | ||||
in = this.getClass().getResourceAsStream(defaultManifest); | in = this.getClass().getResourceAsStream(defaultManifest); | ||||
if ( in == null ) { | if ( in == null ) { | ||||
@@ -695,11 +738,9 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
} | } | ||||
manifest = new Manifest(in); | manifest = new Manifest(in); | ||||
} | |||||
catch (IOException e) { | |||||
} catch (IOException e) { | |||||
throw new BuildException ("Unable to read manifest", e, getLocation()); | throw new BuildException ("Unable to read manifest", e, getLocation()); | ||||
} | |||||
finally { | |||||
} finally { | |||||
if (in != null) { | if (in != null) { | ||||
in.close(); | in.close(); | ||||
} | } | ||||
@@ -728,11 +769,10 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
for (int i = 0, n = innerfiles.length; i < n; i++) { | for (int i = 0, n = innerfiles.length; i < n; i++) { | ||||
//get and clean up innerclass name | //get and clean up innerclass name | ||||
int entryIndex = entryName.lastIndexOf(entryFile.getName()) -1; | |||||
int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1; | |||||
if ( entryIndex < 0) { | if ( entryIndex < 0) { | ||||
entryName = innerfiles[i]; | entryName = innerfiles[i]; | ||||
} | |||||
else { | |||||
} else { | |||||
entryName = entryName.substring(0, entryIndex) + File.separatorChar + innerfiles[i]; | entryName = entryName.substring(0, entryIndex) + File.separatorChar + innerfiles[i]; | ||||
} | } | ||||
// link the file | // 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 '" | String msg = "IOException while processing ejb-jar file '" | ||||
+ jarfile.toString() | + jarfile.toString() | ||||
+ "'. Details: " | + "'. Details: " | ||||
+ ioe.getMessage(); | + ioe.getMessage(); | ||||
throw new BuildException(msg, ioe); | throw new BuildException(msg, ioe); | ||||
} | |||||
finally { | |||||
} finally { | |||||
if (jarStream != null) { | if (jarStream != null) { | ||||
try { | try { | ||||
jarStream.close(); | jarStream.close(); | ||||
} | |||||
catch (IOException closeException) {} | |||||
} catch (IOException closeException) {} | |||||
} | } | ||||
} | } | ||||
} // end of writeJar | } // end of writeJar | ||||
@@ -770,55 +807,35 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
* @param checkEntries files, that are extracted from the deployment descriptor | * @param checkEntries files, that are extracted from the deployment descriptor | ||||
*/ | */ | ||||
protected void checkAndAddDependants(Hashtable checkEntries) | 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(); | Iterator i = checkEntries.keySet().iterator(); | ||||
while (i.hasNext()) { | while (i.hasNext()) { | ||||
String entryName = (String)i.next(); | String entryName = (String)i.next(); | ||||
if (entryName.endsWith(".class")) { | 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. | * being added to the jar. | ||||
* | * | ||||
*/ | */ | ||||
protected ClassLoader getClassLoaderForBuild() | |||||
{ | |||||
protected ClassLoader getClassLoaderForBuild() { | |||||
if (classpathLoader != null) { | if (classpathLoader != null) { | ||||
return classpathLoader; | return classpathLoader; | ||||
} | } | ||||
@@ -840,8 +856,7 @@ public class GenericDeploymentTool implements EJBDeploymentTool { | |||||
// only generate a new ClassLoader if we have a classpath | // only generate a new ClassLoader if we have a classpath | ||||
if (combinedClasspath == null) { | if (combinedClasspath == null) { | ||||
classpathLoader = getClass().getClassLoader(); | classpathLoader = getClass().getClassLoader(); | ||||
} | |||||
else { | |||||
} else { | |||||
classpathLoader = new AntClassLoader(getTask().getProject(), combinedClasspath); | classpathLoader = new AntClassLoader(getTask().getProject(), combinedClasspath); | ||||
} | } | ||||
@@ -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.DirectoryScanner; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.types.FileSet; | 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 | * nested FileSet attribute provides the domain, that is used for searching | ||||
* for dependent classes | * for dependent classes | ||||
* | * | ||||
* @author <a href="mailto:hengels@innovidata.com">Holger Engels</a> | * @author <a href="mailto:hengels@innovidata.com">Holger Engels</a> | ||||
*/ | */ | ||||
public class ClassfileSet extends FileSet { | 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 { | public static class ClassRoot { | ||||
/** The name of the root class */ | |||||
private String rootClass; | private String rootClass; | ||||
/** | |||||
* Set the root class name | |||||
* | |||||
* @param name the name of the root class | |||||
*/ | |||||
public void setClassname(String name) { | public void setClassname(String name) { | ||||
this.rootClass = name; | this.rootClass = name; | ||||
} | } | ||||
/** | |||||
* Get the name of the root class | |||||
* | |||||
* @return the name of the root class. | |||||
*/ | |||||
public String getClassname() { | public String getClassname() { | ||||
return rootClass; | return rootClass; | ||||
} | } | ||||
} | } | ||||
/** | |||||
* Default constructor | |||||
*/ | |||||
public ClassfileSet() { | |||||
} | |||||
/** | |||||
* Create a ClassfileSet from another ClassfileSet | |||||
* | |||||
* @param s the other classfileset | |||||
*/ | |||||
protected ClassfileSet(ClassfileSet s) { | protected ClassfileSet(ClassfileSet s) { | ||||
super(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. | * 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) { | public DirectoryScanner getDirectoryScanner(Project p) { | ||||
DependScanner scanner = new DependScanner(); | DependScanner scanner = new DependScanner(); | ||||
@@ -110,10 +145,20 @@ public class ClassfileSet extends FileSet { | |||||
return scanner; | return scanner; | ||||
} | } | ||||
/** | |||||
* Add a nested root class definition to this class file set | |||||
* | |||||
* @param root the configured class root. | |||||
*/ | |||||
public void addConfiguredRoot(ClassRoot root) { | public void addConfiguredRoot(ClassRoot root) { | ||||
rootClasses.add(root.getClassname()); | rootClasses.add(root.getClassname()); | ||||
} | } | ||||
/** | |||||
* Clone this data type. | |||||
* | |||||
* @return a clone of the class file set | |||||
*/ | |||||
public Object clone() { | public Object clone() { | ||||
if (isReference()) { | if (isReference()) { | ||||
return new ClassfileSet((ClassfileSet) getRef(getProject())); | return new ClassfileSet((ClassfileSet) getRef(getProject())); | ||||
@@ -54,43 +54,43 @@ | |||||
package org.apache.tools.ant.types.optional.depend; | package org.apache.tools.ant.types.optional.depend; | ||||
import java.io.File; | 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.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 | * An interface used to describe the actions required by any type of | ||||
* directory scanner. | * directory scanner. | ||||
* | |||||
* @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @author <a href="mailto:hengels@innovidata.com">Holger Engels</a> | |||||
*/ | */ | ||||
public class DependScanner extends DirectoryScanner { | 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 | * Sets the basedir for scanning. This is the directory that is scanned | ||||
* recursively. | * recursively. | ||||
@@ -100,6 +100,7 @@ public class DependScanner extends DirectoryScanner { | |||||
public void setBasedir(File basedir) { | public void setBasedir(File basedir) { | ||||
this.basedir = basedir; | this.basedir = basedir; | ||||
} | } | ||||
/** | /** | ||||
* Gets the basedir that is used for scanning. | * Gets the basedir that is used for scanning. | ||||
* | * | ||||
@@ -108,11 +109,11 @@ public class DependScanner extends DirectoryScanner { | |||||
public File getBasedir() { return basedir; } | 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; | this.rootClasses = rootClasses; | ||||
} | } | ||||
@@ -125,7 +126,11 @@ public class DependScanner extends DirectoryScanner { | |||||
int count = included.size(); | int count = included.size(); | ||||
String[] files = new String[count]; | String[] files = new String[count]; | ||||
for (int i = 0; i < count; i++) { | 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]); | //System.err.println(" " + files[i]); | ||||
} | } | ||||
return files; | return files; | ||||
@@ -136,68 +141,86 @@ public class DependScanner extends DirectoryScanner { | |||||
* | * | ||||
* @exception IllegalStateException when basedir was set incorrecly | * @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 { | 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) { | |||||
} | |||||
} | } |
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @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; | |||||
} | |||||
} | |||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @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; | |||||
} | |||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
package org.apache.tools.ant.util.depend; | |||||
public interface Filter { | |||||
boolean accept(Object object); | |||||
} |
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @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; | |||||
} | |||||
} | |||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @author <a href="mailto:hengels@innovidata.com">Holger Engels</a> | |||||
* @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('/', '.')); | |||||
} | |||||
} | |||||
@@ -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 | |||||
* <http://www.apache.org/>. | |||||
*/ | |||||
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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
* @author <a href="mailto:hengels@innovidata.com">Holger Engels</a> | |||||
* @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; | |||||
} | |||||
} | |||||