git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271315 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,118 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ClassCPInfo; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPoolEntry; | |||
| /** | |||
| * A ClassFile object stores information about a Java class. The class may be | |||
| * read from a DataInputStream.and written to a DataOutputStream. These are | |||
| * usually streams from a Java class file or a class file component of a Jar | |||
| * file. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassFile | |||
| { | |||
| /** | |||
| * The Magic Value that marks the start of a Java class file | |||
| */ | |||
| private final static int CLASS_MAGIC = 0xCAFEBABE; | |||
| /** | |||
| * The class name for this class. | |||
| */ | |||
| private String className; | |||
| /** | |||
| * This class' constant pool. | |||
| */ | |||
| private ConstantPool constantPool; | |||
| /** | |||
| * Get the classes which this class references. | |||
| * | |||
| * @return The ClassRefs value | |||
| */ | |||
| public ArrayList getClassRefs() | |||
| { | |||
| ArrayList classRefs = new ArrayList(); | |||
| for( int i = 0; i < constantPool.size(); ++i ) | |||
| { | |||
| ConstantPoolEntry entry = constantPool.getEntry( i ); | |||
| if( entry != null && entry.getTag() == ConstantPoolEntry.CONSTANT_Class ) | |||
| { | |||
| ClassCPInfo classEntry = (ClassCPInfo)entry; | |||
| if( !classEntry.getClassName().equals( className ) ) | |||
| { | |||
| classRefs.add( ClassFileUtils.convertSlashName( classEntry.getClassName() ) ); | |||
| } | |||
| } | |||
| } | |||
| return classRefs; | |||
| } | |||
| /** | |||
| * Get the class' fully qualified name in dot format. | |||
| * | |||
| * @return the class name in dot format (eg. java.lang.Object) | |||
| */ | |||
| public String getFullClassName() | |||
| { | |||
| return ClassFileUtils.convertSlashName( className ); | |||
| } | |||
| /** | |||
| * Read the class from a data stream. This method takes an InputStream as | |||
| * input and parses the class from the stream. <p> | |||
| * | |||
| * | |||
| * | |||
| * @param stream an InputStream from which the class will be read | |||
| * @throws IOException if there is a problem reading from the given stream. | |||
| * @throws ClassFormatError if the class cannot be parsed correctly | |||
| */ | |||
| public void read( InputStream stream ) | |||
| throws IOException, ClassFormatError | |||
| { | |||
| DataInputStream classStream = new DataInputStream( stream ); | |||
| if( classStream.readInt() != CLASS_MAGIC ) | |||
| { | |||
| throw new ClassFormatError( "No Magic Code Found - probably not a Java class file." ); | |||
| } | |||
| // right we have a good looking class file. | |||
| int minorVersion = classStream.readUnsignedShort(); | |||
| int majorVersion = classStream.readUnsignedShort(); | |||
| // read the constant pool in and resolve it | |||
| constantPool = new ConstantPool(); | |||
| constantPool.read( classStream ); | |||
| constantPool.resolve(); | |||
| int accessFlags = classStream.readUnsignedShort(); | |||
| int thisClassIndex = classStream.readUnsignedShort(); | |||
| int superClassIndex = classStream.readUnsignedShort(); | |||
| className = ( (ClassCPInfo)constantPool.getEntry( thisClassIndex ) ).getClassName(); | |||
| } | |||
| } | |||
| @@ -1,14 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| public interface ClassFileIterator | |||
| { | |||
| ClassFile getNextClassFile(); | |||
| } | |||
| @@ -1,44 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| /** | |||
| * Utility class file routines. This class porovides a number of static utility | |||
| * methods to convert between the formats used in the Java class file format and | |||
| * those commonly used in Java programming. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassFileUtils | |||
| { | |||
| /** | |||
| * Convert a class name from java source file dot notation to class file | |||
| * slash notation.. | |||
| * | |||
| * @param dotName the class name in dot notation (eg. java.lang.Object). | |||
| * @return the class name in slash notation (eg. java/lang/Object). | |||
| */ | |||
| public static String convertDotName( String dotName ) | |||
| { | |||
| return dotName.replace( '.', '/' ); | |||
| } | |||
| /** | |||
| * Convert a class name from class file slash notation to java source file | |||
| * dot notation. | |||
| * | |||
| * @param name Description of Parameter | |||
| * @return the class name in dot notation (eg. java.lang.Object). | |||
| */ | |||
| public static String convertSlashName( String name ) | |||
| { | |||
| return name.replace( '\\', '.' ).replace( '/', '.' ); | |||
| } | |||
| } | |||
| @@ -1,753 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.net.URL; | |||
| import java.net.URLClassLoader; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.ant.taskdefs.MatchingTask; | |||
| import org.apache.tools.ant.types.DirectoryScanner; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.PathUtil; | |||
| /** | |||
| * Generate a dependency file for a given set of classes | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class Depend extends MatchingTask | |||
| { | |||
| /** | |||
| * constants used with the cache file | |||
| */ | |||
| private final static String CACHE_FILE_NAME = "dependencies.txt"; | |||
| private final static String CLASSNAME_PREPEND = "||:"; | |||
| /** | |||
| * indicates that the dependency relationships should be extended beyond | |||
| * direct dependencies to include all classes. So if A directly affects B | |||
| * abd B directly affects C, then A indirectly affects C. | |||
| */ | |||
| private boolean closure = false; | |||
| /** | |||
| * Flag which controls whether the reversed dependencies should be dumped to | |||
| * the log | |||
| */ | |||
| private boolean dump = false; | |||
| /** | |||
| * A map which gives for every class a list of te class which it affects. | |||
| */ | |||
| private Hashtable affectedClassMap; | |||
| /** | |||
| * The directory which contains the dependency cache. | |||
| */ | |||
| private File cache; | |||
| /** | |||
| * A map which gives information about a class | |||
| */ | |||
| private Hashtable classFileInfoMap; | |||
| /** | |||
| * A map which gives the list of jars and classes from the classpath that a | |||
| * class depends upon | |||
| */ | |||
| private Hashtable classpathDependencies; | |||
| /** | |||
| * The classpath to look for additional dependencies | |||
| */ | |||
| private Path dependClasspath; | |||
| /** | |||
| * The path where compiled class files exist. | |||
| */ | |||
| private Path destPath; | |||
| /** | |||
| * The list of classes which are out of date. | |||
| */ | |||
| private Hashtable outOfDateClasses; | |||
| /** | |||
| * The path where source files exist | |||
| */ | |||
| private Path srcPath; | |||
| public void setCache( File cache ) | |||
| { | |||
| this.cache = cache; | |||
| } | |||
| /** | |||
| * Set the classpath to be used for this dependency check. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| throws TaskException | |||
| { | |||
| if( dependClasspath == null ) | |||
| { | |||
| dependClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| dependClasspath.append( classpath ); | |||
| } | |||
| } | |||
| public void setClosure( boolean closure ) | |||
| { | |||
| this.closure = closure; | |||
| } | |||
| /** | |||
| * Set the destination directory where the compiled java files exist. | |||
| * | |||
| * @param destPath The new DestDir value | |||
| */ | |||
| public void setDestDir( Path destPath ) | |||
| { | |||
| this.destPath = destPath; | |||
| } | |||
| /** | |||
| * Flag to indicate whether the reverse dependency list should be dumped to | |||
| * debug | |||
| * | |||
| * @param dump The new Dump value | |||
| */ | |||
| public void setDump( boolean dump ) | |||
| { | |||
| this.dump = dump; | |||
| } | |||
| /** | |||
| * Set the source dirs to find the source Java files. | |||
| * | |||
| * @param srcPath The new Srcdir value | |||
| */ | |||
| public void setSrcdir( Path srcPath ) | |||
| { | |||
| this.srcPath = srcPath; | |||
| } | |||
| /** | |||
| * Gets the classpath to be used for this dependency check. | |||
| * | |||
| * @return The Classpath value | |||
| */ | |||
| public Path getClasspath() | |||
| { | |||
| return dependClasspath; | |||
| } | |||
| /** | |||
| * Creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| throws TaskException | |||
| { | |||
| if( dependClasspath == null ) | |||
| { | |||
| dependClasspath = new Path(); | |||
| } | |||
| Path path1 = dependClasspath; | |||
| final Path path = new Path(); | |||
| path1.addPath( path ); | |||
| return path; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception TaskException Thrown in unrecovrable error. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| long start = System.currentTimeMillis(); | |||
| String[] srcPathList = srcPath.list(); | |||
| if( srcPathList.length == 0 ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| if( destPath == null ) | |||
| { | |||
| destPath = srcPath; | |||
| } | |||
| if( cache != null && cache.exists() && !cache.isDirectory() ) | |||
| { | |||
| throw new TaskException( "The cache, if specified, must point to a directory" ); | |||
| } | |||
| if( cache != null && !cache.exists() ) | |||
| { | |||
| cache.mkdirs(); | |||
| } | |||
| determineDependencies(); | |||
| if( dump ) | |||
| { | |||
| getLogger().debug( "Reverse Dependency Dump for " + affectedClassMap.size() + " classes:" ); | |||
| for( Enumeration e = affectedClassMap.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| getLogger().debug( " Class " + className + " affects:" ); | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( className ); | |||
| for( Enumeration e2 = affectedClasses.keys(); e2.hasMoreElements(); ) | |||
| { | |||
| String affectedClass = (String)e2.nextElement(); | |||
| ClassFileInfo info = (ClassFileInfo)affectedClasses.get( affectedClass ); | |||
| getLogger().debug( " " + affectedClass + " in " + info.absoluteFile.getPath() ); | |||
| } | |||
| } | |||
| if( classpathDependencies != null ) | |||
| { | |||
| getLogger().debug( "Classpath file dependencies (Forward):" ); | |||
| for( Enumeration e = classpathDependencies.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| getLogger().debug( " Class " + className + " depends on:" ); | |||
| Hashtable dependencies = (Hashtable)classpathDependencies.get( className ); | |||
| for( Enumeration e2 = dependencies.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| File classpathFile = (File)e2.nextElement(); | |||
| getLogger().debug( " " + classpathFile.getPath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // we now need to scan for out of date files. When we have the list | |||
| // we go through and delete all class files which are affected by these files. | |||
| outOfDateClasses = new Hashtable(); | |||
| for( int i = 0; i < srcPathList.length; i++ ) | |||
| { | |||
| File srcDir = (File)resolveFile( srcPathList[ i ] ); | |||
| if( srcDir.exists() ) | |||
| { | |||
| DirectoryScanner ds = this.getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, files ); | |||
| } | |||
| } | |||
| // now check classpath file dependencies | |||
| if( classpathDependencies != null ) | |||
| { | |||
| for( Enumeration e = classpathDependencies.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| if( !outOfDateClasses.containsKey( className ) ) | |||
| { | |||
| ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| // if we have no info about the class - it may have been deleted already and we | |||
| // are using cached info. | |||
| if( info != null ) | |||
| { | |||
| Hashtable dependencies = (Hashtable)classpathDependencies.get( className ); | |||
| for( Enumeration e2 = dependencies.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| File classpathFile = (File)e2.nextElement(); | |||
| if( classpathFile.lastModified() > info.absoluteFile.lastModified() ) | |||
| { | |||
| getLogger().debug( "Class " + className + " is out of date with respect to " + classpathFile ); | |||
| outOfDateClasses.put( className, className ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // we now have a complete list of classes which are out of date | |||
| // We scan through the affected classes, deleting any affected classes. | |||
| int count = deleteAllAffectedFiles(); | |||
| long duration = ( System.currentTimeMillis() - start ) / 1000; | |||
| getLogger().info( "Deleted " + count + " out of date files in " + duration + " seconds" ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| } | |||
| /** | |||
| * Scans the directory looking for source files that are newer than their | |||
| * class files. The results are returned in the class variable compileList | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| protected void scanDir( File srcDir, String files[] ) | |||
| { | |||
| long now = System.currentTimeMillis(); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File srcFile = new File( srcDir, files[ i ] ); | |||
| if( files[ i ].endsWith( ".java" ) ) | |||
| { | |||
| String filePath = srcFile.getPath(); | |||
| String className = filePath.substring( srcDir.getPath().length() + 1, | |||
| filePath.length() - ".java".length() ); | |||
| className = ClassFileUtils.convertSlashName( className ); | |||
| ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| if( info == null ) | |||
| { | |||
| // there was no class file. add this class to the list | |||
| outOfDateClasses.put( className, className ); | |||
| } | |||
| else | |||
| { | |||
| if( srcFile.lastModified() > info.absoluteFile.lastModified() ) | |||
| { | |||
| outOfDateClasses.put( className, className ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Get the list of class files we are going to analyse. | |||
| * | |||
| * @param classLocations a path structure containing all the directories | |||
| * where classes can be found. | |||
| * @return a vector containing the classes to analyse. | |||
| */ | |||
| private ArrayList getClassFiles( Path classLocations ) | |||
| throws TaskException | |||
| { | |||
| // break the classLocations into its components. | |||
| String[] classLocationsList = classLocations.list(); | |||
| ArrayList classFileList = new ArrayList(); | |||
| for( int i = 0; i < classLocationsList.length; ++i ) | |||
| { | |||
| File dir = new File( classLocationsList[ i ] ); | |||
| if( dir.isDirectory() ) | |||
| { | |||
| addClassFiles( classFileList, dir, dir ); | |||
| } | |||
| } | |||
| return classFileList; | |||
| } | |||
| /** | |||
| * Add the list of class files from the given directory to the class file | |||
| * vector, including any subdirectories. | |||
| * | |||
| * @param classFileList The feature to be added to the ClassFiles attribute | |||
| * @param dir The feature to be added to the ClassFiles attribute | |||
| * @param root The feature to be added to the ClassFiles attribute | |||
| */ | |||
| private void addClassFiles( ArrayList classFileList, File dir, File root ) | |||
| { | |||
| String[] filesInDir = dir.list(); | |||
| if( filesInDir != null ) | |||
| { | |||
| int length = filesInDir.length; | |||
| for( int i = 0; i < length; ++i ) | |||
| { | |||
| File file = new File( dir, filesInDir[ i ] ); | |||
| if( file.isDirectory() ) | |||
| { | |||
| addClassFiles( classFileList, file, root ); | |||
| } | |||
| else if( file.getName().endsWith( ".class" ) ) | |||
| { | |||
| ClassFileInfo info = new ClassFileInfo(); | |||
| info.absoluteFile = file; | |||
| info.relativeName = file.getPath().substring( root.getPath().length() + 1, | |||
| file.getPath().length() - 6 ); | |||
| info.className = ClassFileUtils.convertSlashName( info.relativeName ); | |||
| classFileList.add( info ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private int deleteAffectedFiles( String className ) | |||
| { | |||
| int count = 0; | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( className ); | |||
| if( affectedClasses != null ) | |||
| { | |||
| for( Enumeration e = affectedClasses.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String affectedClassName = (String)e.nextElement(); | |||
| ClassFileInfo affectedClassInfo = (ClassFileInfo)affectedClasses.get( affectedClassName ); | |||
| if( affectedClassInfo.absoluteFile.exists() ) | |||
| { | |||
| getLogger().debug( "Deleting file " + affectedClassInfo.absoluteFile.getPath() + " since " + className + " out of date" ); | |||
| affectedClassInfo.absoluteFile.delete(); | |||
| count++; | |||
| if( closure ) | |||
| { | |||
| count += deleteAffectedFiles( affectedClassName ); | |||
| } | |||
| else | |||
| { | |||
| // without closure we may delete an inner class but not the | |||
| // top level class which would not trigger a recompile. | |||
| if( affectedClassName.indexOf( "$" ) != -1 ) | |||
| { | |||
| // need to delete the main class | |||
| String topLevelClassName | |||
| = affectedClassName.substring( 0, affectedClassName.indexOf( "$" ) ); | |||
| getLogger().debug( "Top level class = " + topLevelClassName ); | |||
| ClassFileInfo topLevelClassInfo | |||
| = (ClassFileInfo)classFileInfoMap.get( topLevelClassName ); | |||
| if( topLevelClassInfo != null && | |||
| topLevelClassInfo.absoluteFile.exists() ) | |||
| { | |||
| getLogger().debug( "Deleting file " + topLevelClassInfo.absoluteFile.getPath() + " since " + "one of its inner classes was removed" ); | |||
| topLevelClassInfo.absoluteFile.delete(); | |||
| count++; | |||
| if( closure ) | |||
| { | |||
| count += deleteAffectedFiles( topLevelClassName ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| private int deleteAllAffectedFiles() | |||
| { | |||
| int count = 0; | |||
| for( Enumeration e = outOfDateClasses.elements(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| count += deleteAffectedFiles( className ); | |||
| ClassFileInfo classInfo = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| if( classInfo != null && classInfo.absoluteFile.exists() ) | |||
| { | |||
| classInfo.absoluteFile.delete(); | |||
| count++; | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| /** | |||
| * Determine the dependencies between classes. Class dependencies are | |||
| * determined by examining the class references in a class file to other | |||
| * classes | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private void determineDependencies() | |||
| throws IOException, TaskException | |||
| { | |||
| affectedClassMap = new Hashtable(); | |||
| classFileInfoMap = new Hashtable(); | |||
| boolean cacheDirty = false; | |||
| Hashtable dependencyMap = new Hashtable(); | |||
| File depCacheFile = null; | |||
| boolean depCacheFileExists = true; | |||
| long depCacheFileLastModified = Long.MAX_VALUE; | |||
| // read the dependency cache from the disk | |||
| if( cache != null ) | |||
| { | |||
| dependencyMap = readCachedDependencies(); | |||
| depCacheFile = new File( cache, CACHE_FILE_NAME ); | |||
| depCacheFileExists = depCacheFile.exists(); | |||
| depCacheFileLastModified = depCacheFile.lastModified(); | |||
| } | |||
| for( Iterator e = getClassFiles( destPath ).iterator(); e.hasNext(); ) | |||
| { | |||
| ClassFileInfo info = (ClassFileInfo)e.next(); | |||
| getLogger().debug( "Adding class info for " + info.className ); | |||
| classFileInfoMap.put( info.className, info ); | |||
| ArrayList dependencyList = null; | |||
| if( cache != null ) | |||
| { | |||
| // try to read the dependency info from the map if it is not out of date | |||
| if( depCacheFileExists && depCacheFileLastModified > info.absoluteFile.lastModified() ) | |||
| { | |||
| // depFile exists and is newer than the class file | |||
| // need to get dependency list from the map. | |||
| dependencyList = (ArrayList)dependencyMap.get( info.className ); | |||
| } | |||
| } | |||
| if( dependencyList == null ) | |||
| { | |||
| // not cached - so need to read directly from the class file | |||
| FileInputStream inFileStream = null; | |||
| try | |||
| { | |||
| inFileStream = new FileInputStream( info.absoluteFile ); | |||
| ClassFile classFile = new ClassFile(); | |||
| classFile.read( inFileStream ); | |||
| dependencyList = classFile.getClassRefs(); | |||
| if( dependencyList != null ) | |||
| { | |||
| cacheDirty = true; | |||
| dependencyMap.put( info.className, dependencyList ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( inFileStream != null ) | |||
| { | |||
| inFileStream.close(); | |||
| } | |||
| } | |||
| } | |||
| // This class depends on each class in the dependency list. For each | |||
| // one of those, add this class into their affected classes list | |||
| for( Iterator depEnum = dependencyList.iterator(); depEnum.hasNext(); ) | |||
| { | |||
| String dependentClass = (String)depEnum.next(); | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( dependentClass ); | |||
| if( affectedClasses == null ) | |||
| { | |||
| affectedClasses = new Hashtable(); | |||
| affectedClassMap.put( dependentClass, affectedClasses ); | |||
| } | |||
| affectedClasses.put( info.className, info ); | |||
| } | |||
| } | |||
| classpathDependencies = null; | |||
| if( dependClasspath != null ) | |||
| { | |||
| // now determine which jars each class depends upon | |||
| classpathDependencies = new Hashtable(); | |||
| final URL[] urls = PathUtil.toURLs( dependClasspath ); | |||
| final ClassLoader classLoader = new URLClassLoader( urls ); | |||
| Hashtable classpathFileCache = new Hashtable(); | |||
| Object nullFileMarker = new Object(); | |||
| for( Enumeration e = dependencyMap.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| ArrayList dependencyList = (ArrayList)dependencyMap.get( className ); | |||
| Hashtable dependencies = new Hashtable(); | |||
| classpathDependencies.put( className, dependencies ); | |||
| for( Iterator e2 = dependencyList.iterator(); e2.hasNext(); ) | |||
| { | |||
| String dependency = (String)e2.next(); | |||
| Object classpathFileObject = classpathFileCache.get( dependency ); | |||
| if( classpathFileObject == null ) | |||
| { | |||
| classpathFileObject = nullFileMarker; | |||
| if( !dependency.startsWith( "java." ) && !dependency.startsWith( "javax." ) ) | |||
| { | |||
| final String name = dependency.replace( '.', '/' ) + ".class"; | |||
| URL classURL = classLoader.getResource( name ); | |||
| if( classURL != null ) | |||
| { | |||
| if( classURL.getProtocol().equals( "jar" ) ) | |||
| { | |||
| String jarFilePath = classURL.getFile(); | |||
| if( jarFilePath.startsWith( "file:" ) ) | |||
| { | |||
| int classMarker = jarFilePath.indexOf( '!' ); | |||
| jarFilePath = jarFilePath.substring( 5, classMarker ); | |||
| } | |||
| classpathFileObject = new File( jarFilePath ); | |||
| } | |||
| else if( classURL.getProtocol().equals( "file" ) ) | |||
| { | |||
| String classFilePath = classURL.getFile(); | |||
| classpathFileObject = new File( classFilePath ); | |||
| } | |||
| getLogger().debug( "Class " + className + " depends on " + classpathFileObject + " due to " + dependency ); | |||
| } | |||
| } | |||
| classpathFileCache.put( dependency, classpathFileObject ); | |||
| } | |||
| if( classpathFileObject != null && classpathFileObject != nullFileMarker ) | |||
| { | |||
| // we need to add this jar to the list for this class. | |||
| File jarFile = (File)classpathFileObject; | |||
| dependencies.put( jarFile, jarFile ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // write the dependency cache to the disk | |||
| if( cache != null && cacheDirty ) | |||
| { | |||
| writeCachedDependencies( dependencyMap ); | |||
| } | |||
| } | |||
| /** | |||
| * Read the dependencies from cache file | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private Hashtable readCachedDependencies() | |||
| throws IOException | |||
| { | |||
| Hashtable dependencyMap = new Hashtable(); | |||
| if( cache != null ) | |||
| { | |||
| File depFile = new File( cache, CACHE_FILE_NAME ); | |||
| BufferedReader in = null; | |||
| if( depFile.exists() ) | |||
| { | |||
| try | |||
| { | |||
| in = new BufferedReader( new FileReader( depFile ) ); | |||
| String line = null; | |||
| ArrayList dependencyList = null; | |||
| String className = null; | |||
| int prependLength = CLASSNAME_PREPEND.length(); | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| if( line.startsWith( CLASSNAME_PREPEND ) ) | |||
| { | |||
| dependencyList = new ArrayList(); | |||
| className = line.substring( prependLength ); | |||
| dependencyMap.put( className, dependencyList ); | |||
| } | |||
| else | |||
| { | |||
| dependencyList.add( line ); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( in != null ) | |||
| { | |||
| in.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return dependencyMap; | |||
| } | |||
| /** | |||
| * Write the dependencies to cache file | |||
| * | |||
| * @param dependencyMap Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private void writeCachedDependencies( Hashtable dependencyMap ) | |||
| throws IOException | |||
| { | |||
| if( cache != null ) | |||
| { | |||
| PrintWriter pw = null; | |||
| try | |||
| { | |||
| cache.mkdirs(); | |||
| File depFile = new File( cache, CACHE_FILE_NAME ); | |||
| pw = new PrintWriter( new FileWriter( depFile ) ); | |||
| for( Enumeration deps = dependencyMap.keys(); deps.hasMoreElements(); ) | |||
| { | |||
| String className = (String)deps.nextElement(); | |||
| pw.println( CLASSNAME_PREPEND + className ); | |||
| ArrayList dependencyList = (ArrayList)dependencyMap.get( className ); | |||
| int size = dependencyList.size(); | |||
| for( int x = 0; x < size; x++ ) | |||
| { | |||
| pw.println( dependencyList.get( x ) ); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( pw != null ) | |||
| { | |||
| pw.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * A class (struct) user to manage information about a class | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class ClassFileInfo | |||
| { | |||
| /** | |||
| * The file where the class file is stored in the file system | |||
| */ | |||
| public File absoluteFile; | |||
| /** | |||
| * The Java class name of this class | |||
| */ | |||
| public String className; | |||
| /** | |||
| * The location of the file relative to its base directory - the root of | |||
| * the package namespace | |||
| */ | |||
| public String relativeName; | |||
| } | |||
| } | |||
| @@ -1,186 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.Stack; | |||
| /** | |||
| * An iterator which iterates through the contents of a java directory. The | |||
| * iterator should be created with the directory at the root of the Java | |||
| * namespace. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class DirectoryIterator implements ClassFileIterator | |||
| { | |||
| /** | |||
| * The length of the root directory. This is used to remove the root | |||
| * directory from full paths. | |||
| */ | |||
| int rootLength; | |||
| /** | |||
| * The current directory iterator. As directories encounter lower level | |||
| * directories, the current iterator is pushed onto the iterator stack and a | |||
| * new iterator over the sub directory becomes the current directory. This | |||
| * implements a depth first traversal of the directory namespace. | |||
| */ | |||
| private Iterator currentEnum; | |||
| /** | |||
| * This is a stack of current iterators supporting the depth first traversal | |||
| * of the directory tree. | |||
| */ | |||
| private Stack enumStack; | |||
| /** | |||
| * Creates a directory iterator. The directory iterator is created to scan | |||
| * the root directory. If the changeInto flag is given, then the entries | |||
| * returned will be relative to this directory and not the current | |||
| * directory. | |||
| * | |||
| * @param rootDirectory the root if the directory namespace which is to be | |||
| * iterated over | |||
| * @param changeInto if true then the returned entries will be relative to | |||
| * the rootDirectory and not the current directory. | |||
| * @exception IOException Description of Exception | |||
| * @throws IOException if there is a problem reading the directory | |||
| * information. | |||
| */ | |||
| public DirectoryIterator( File rootDirectory, boolean changeInto ) | |||
| throws IOException | |||
| { | |||
| super(); | |||
| enumStack = new Stack(); | |||
| if( rootDirectory.isAbsolute() || changeInto ) | |||
| { | |||
| rootLength = rootDirectory.getPath().length() + 1; | |||
| } | |||
| else | |||
| { | |||
| rootLength = 0; | |||
| } | |||
| ArrayList filesInRoot = getDirectoryEntries( rootDirectory ); | |||
| currentEnum = filesInRoot.iterator(); | |||
| } | |||
| /** | |||
| * Template method to allow subclasses to supply elements for the iteration. | |||
| * The directory iterator maintains a stack of iterators covering each level | |||
| * in the directory hierarchy. The current iterator covers the current | |||
| * directory being scanned. If the next entry in that directory is a | |||
| * subdirectory, the current iterator is pushed onto the stack and a new | |||
| * iterator is created for the subdirectory. If the entry is a file, it is | |||
| * returned as the next element and the iterator remains valid. If there are | |||
| * no more entries in the current directory, the topmost iterator on the | |||
| * statck is popped off to become the current iterator. | |||
| * | |||
| * @return the next ClassFile in the iteration. | |||
| */ | |||
| public ClassFile getNextClassFile() | |||
| { | |||
| ClassFile next = null; | |||
| try | |||
| { | |||
| while( next == null ) | |||
| { | |||
| if( currentEnum.hasNext() ) | |||
| { | |||
| File element = (File)currentEnum.next(); | |||
| if( element.isDirectory() ) | |||
| { | |||
| // push the current iterator onto the stack and then | |||
| // iterate through this directory. | |||
| enumStack.push( currentEnum ); | |||
| ArrayList files = getDirectoryEntries( element ); | |||
| currentEnum = files.iterator(); | |||
| } | |||
| else | |||
| { | |||
| // we have a file. create a stream for it | |||
| FileInputStream inFileStream = new FileInputStream( element ); | |||
| if( element.getName().endsWith( ".class" ) ) | |||
| { | |||
| // create a data input stream from the jar input stream | |||
| ClassFile javaClass = new ClassFile(); | |||
| javaClass.read( inFileStream ); | |||
| next = javaClass; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // this iterator is exhausted. Can we pop one off the stack | |||
| if( enumStack.empty() ) | |||
| { | |||
| break; | |||
| } | |||
| else | |||
| { | |||
| currentEnum = (Iterator)enumStack.pop(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| next = null; | |||
| } | |||
| return next; | |||
| } | |||
| /** | |||
| * Get a vector covering all the entries (files and subdirectories in a | |||
| * directory). | |||
| * | |||
| * @param directory the directory to be scanned. | |||
| * @return a vector containing File objects for each entry in the directory. | |||
| */ | |||
| private ArrayList getDirectoryEntries( File directory ) | |||
| { | |||
| ArrayList files = new ArrayList(); | |||
| // File[] filesInDir = directory.listFiles(); | |||
| String[] filesInDir = directory.list(); | |||
| if( filesInDir != null ) | |||
| { | |||
| int length = filesInDir.length; | |||
| for( int i = 0; i < length; ++i ) | |||
| { | |||
| files.add( new File( directory, filesInDir[ i ] ) ); | |||
| } | |||
| } | |||
| return files; | |||
| } | |||
| } | |||
| @@ -1,95 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipInputStream; | |||
| /** | |||
| * A class file iterator which iterates through the contents of a Java jar file. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class JarFileIterator implements ClassFileIterator | |||
| { | |||
| private ZipInputStream jarStream; | |||
| public JarFileIterator( InputStream stream ) | |||
| throws IOException | |||
| { | |||
| super(); | |||
| jarStream = new ZipInputStream( stream ); | |||
| } | |||
| public ClassFile getNextClassFile() | |||
| { | |||
| ZipEntry jarEntry; | |||
| ClassFile next = null; | |||
| try | |||
| { | |||
| jarEntry = jarStream.getNextEntry(); | |||
| while( next == null && jarEntry != null ) | |||
| { | |||
| String entryName = jarEntry.getName(); | |||
| if( !jarEntry.isDirectory() && entryName.endsWith( ".class" ) ) | |||
| { | |||
| // create a data input stream from the jar input stream | |||
| ClassFile javaClass = new ClassFile(); | |||
| javaClass.read( jarStream ); | |||
| next = javaClass; | |||
| } | |||
| else | |||
| { | |||
| jarEntry = jarStream.getNextEntry(); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| String message = e.getMessage(); | |||
| String text = e.getClass().getName(); | |||
| if( message != null ) | |||
| { | |||
| text += ": " + message; | |||
| } | |||
| throw new RuntimeException( "Problem reading JAR file: " + text ); | |||
| } | |||
| return next; | |||
| } | |||
| private byte[] getEntryBytes( InputStream stream ) | |||
| throws IOException | |||
| { | |||
| byte[] buffer = new byte[ 8192 ]; | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream( 2048 ); | |||
| int n; | |||
| while( ( n = stream.read( buffer, 0, buffer.length ) ) != -1 ) | |||
| { | |||
| baos.write( buffer, 0, n ); | |||
| } | |||
| return baos.toByteArray(); | |||
| } | |||
| } | |||
| @@ -1,89 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * The constant pool entry which stores class information. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassCPInfo extends ConstantPoolEntry | |||
| { | |||
| /** | |||
| * The class' name. This will be only valid if the entry has been resolved | |||
| * against the constant pool. | |||
| */ | |||
| private String className; | |||
| /** | |||
| * The index into the constant pool where this class' name is stored. If the | |||
| * class name is changed, this entry is invalid until this entry is | |||
| * connected to a constant pool. | |||
| */ | |||
| private int index; | |||
| /** | |||
| * Constructor. Sets the tag value for this entry to type Class | |||
| */ | |||
| public ClassCPInfo() | |||
| { | |||
| super( CONSTANT_Class, 1 ); | |||
| } | |||
| /** | |||
| * Get the class name of this entry. | |||
| * | |||
| * @return the class' name. | |||
| */ | |||
| public String getClassName() | |||
| { | |||
| return className; | |||
| } | |||
| /** | |||
| * Read the entry from a stream. | |||
| * | |||
| * @param cpStream the stream containing the constant pool entry to be read. | |||
| * @exception IOException thrown if there is a problem reading the entry | |||
| * from the stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| index = cpStream.readUnsignedShort(); | |||
| className = "unresolved"; | |||
| } | |||
| /** | |||
| * Resolve this class info against the given constant pool. | |||
| * | |||
| * @param constantPool the constant pool with which to resolve the class. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| className = ( (Utf8CPInfo)constantPool.getEntry( index ) ).getValue(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Generate a string readable version of this entry | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Class Constant Pool Entry for " + className + "[" + index + "]"; | |||
| } | |||
| } | |||
| @@ -1,57 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| /** | |||
| * A Constant Pool entry which represents a constant value. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public abstract class ConstantCPInfo extends ConstantPoolEntry | |||
| { | |||
| /** | |||
| * The entry's untyped value. Each subclass interprets the constant value | |||
| * based on the subclass's type. The value here must be compatible. | |||
| */ | |||
| private Object value; | |||
| /** | |||
| * Initialise the constant entry. | |||
| * | |||
| * @param tagValue the constant pool entry type to be used. | |||
| * @param entries the number of constant pool entry slots occupied by this | |||
| * entry. | |||
| */ | |||
| protected ConstantCPInfo( int tagValue, int entries ) | |||
| { | |||
| super( tagValue, entries ); | |||
| } | |||
| /** | |||
| * Set the constant value. | |||
| * | |||
| * @param newValue the new untyped value of this constant. | |||
| */ | |||
| public void setValue( Object newValue ) | |||
| { | |||
| value = newValue; | |||
| } | |||
| /** | |||
| * Get the value of the constant. | |||
| * | |||
| * @return the value of the constant (untyped). | |||
| */ | |||
| public Object getValue() | |||
| { | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,374 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| /** | |||
| * The constant pool of a Java class. The constant pool is a collection of | |||
| * constants used in a Java class file. It stores strings, constant values, | |||
| * class names, method names, field names etc. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @see <a href="http://java.sun.com/docs/books/vmspec/">The Java Virtual | |||
| * Machine Specification</a> | |||
| */ | |||
| public class ConstantPool | |||
| { | |||
| /** | |||
| * The entries in the constant pool. | |||
| */ | |||
| private ArrayList entries; | |||
| /** | |||
| * A Hashtable of UTF8 entries - used to get constant pool indexes of the | |||
| * UTF8 values quickly | |||
| */ | |||
| private Hashtable utf8Indexes; | |||
| /** | |||
| * Initialise the constant pool. | |||
| */ | |||
| public ConstantPool() | |||
| { | |||
| entries = new ArrayList(); | |||
| // The zero index is never present in the constant pool itself so | |||
| // we add a null entry for it | |||
| entries.add( null ); | |||
| utf8Indexes = new Hashtable(); | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_Class entry in the constant pool. | |||
| * | |||
| * @param className the name of the class for which the class entry index is | |||
| * required. | |||
| * @return the index at which the given class entry occurs in the constant | |||
| * pool or -1 if the value does not occur. | |||
| */ | |||
| public int getClassEntry( String className ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof ClassCPInfo ) | |||
| { | |||
| ClassCPInfo classinfo = (ClassCPInfo)element; | |||
| if( classinfo.getClassName().equals( className ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given constant value entry in the constant pool. | |||
| * | |||
| * @param constantValue the constant value for which the index is required. | |||
| * @return the index at which the given value entry occurs in the constant | |||
| * pool or -1 if the value does not occur. | |||
| */ | |||
| public int getConstantEntry( Object constantValue ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof ConstantCPInfo ) | |||
| { | |||
| ConstantCPInfo constantEntry = (ConstantCPInfo)element; | |||
| if( constantEntry.getValue().equals( constantValue ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get an constant pool entry at a particular index. | |||
| * | |||
| * @param index the index into the constant pool. | |||
| * @return the constant pool entry at that index. | |||
| */ | |||
| public ConstantPoolEntry getEntry( int index ) | |||
| { | |||
| return (ConstantPoolEntry)entries.get( index ); | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_FieldRef entry in the constant pool. | |||
| * | |||
| * @param fieldClassName the name of the class which contains the field | |||
| * being referenced. | |||
| * @param fieldName the name of the field being referenced. | |||
| * @param fieldType the type descriptor of the field being referenced. | |||
| * @return the index at which the given field ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getFieldRefEntry( String fieldClassName, String fieldName, String fieldType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof FieldRefCPInfo ) | |||
| { | |||
| FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo)element; | |||
| if( fieldRefEntry.getFieldClassName().equals( fieldClassName ) && fieldRefEntry.getFieldName().equals( fieldName ) | |||
| && fieldRefEntry.getFieldType().equals( fieldType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_InterfaceMethodRef entry in the | |||
| * constant pool. | |||
| * | |||
| * @param interfaceMethodClassName the name of the interface which contains | |||
| * the method being referenced. | |||
| * @param interfaceMethodName the name of the method being referenced. | |||
| * @param interfaceMethodType the type descriptor of the metho dbeing | |||
| * referenced. | |||
| * @return the index at which the given method ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getInterfaceMethodRefEntry( String interfaceMethodClassName, String interfaceMethodName, String interfaceMethodType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof InterfaceMethodRefCPInfo ) | |||
| { | |||
| InterfaceMethodRefCPInfo interfaceMethodRefEntry = (InterfaceMethodRefCPInfo)element; | |||
| if( interfaceMethodRefEntry.getInterfaceMethodClassName().equals( interfaceMethodClassName ) | |||
| && interfaceMethodRefEntry.getInterfaceMethodName().equals( interfaceMethodName ) | |||
| && interfaceMethodRefEntry.getInterfaceMethodType().equals( interfaceMethodType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_MethodRef entry in the constant pool. | |||
| * | |||
| * @param methodClassName the name of the class which contains the method | |||
| * being referenced. | |||
| * @param methodName the name of the method being referenced. | |||
| * @param methodType the type descriptor of the metho dbeing referenced. | |||
| * @return the index at which the given method ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getMethodRefEntry( String methodClassName, String methodName, String methodType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof MethodRefCPInfo ) | |||
| { | |||
| MethodRefCPInfo methodRefEntry = (MethodRefCPInfo)element; | |||
| if( methodRefEntry.getMethodClassName().equals( methodClassName ) | |||
| && methodRefEntry.getMethodName().equals( methodName ) && methodRefEntry.getMethodType().equals( methodType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_NameAndType entry in the constant pool. | |||
| * | |||
| * @param name the name | |||
| * @param type the type | |||
| * @return the index at which the given NameAndType entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getNameAndTypeEntry( String name, String type ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof NameAndTypeCPInfo ) | |||
| { | |||
| NameAndTypeCPInfo nameAndTypeEntry = (NameAndTypeCPInfo)element; | |||
| if( nameAndTypeEntry.getName().equals( name ) && nameAndTypeEntry.getType().equals( type ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given UTF8 constant pool entry. | |||
| * | |||
| * @param value the string value of the UTF8 entry. | |||
| * @return the index at which the given string occurs in the constant pool | |||
| * or -1 if the value does not occur. | |||
| */ | |||
| public int getUTF8Entry( String value ) | |||
| { | |||
| int index = -1; | |||
| Integer indexInteger = (Integer)utf8Indexes.get( value ); | |||
| if( indexInteger != null ) | |||
| { | |||
| index = indexInteger.intValue(); | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Add an entry to the constant pool. | |||
| * | |||
| * @param entry the new entry to be added to the constant pool. | |||
| * @return the index into the constant pool at which the entry is stored. | |||
| */ | |||
| public int addEntry( ConstantPoolEntry entry ) | |||
| { | |||
| int index = entries.size(); | |||
| entries.add( entry ); | |||
| int numSlots = entry.getNumEntries(); | |||
| // add null entries for any additional slots required. | |||
| for( int j = 0; j < numSlots - 1; ++j ) | |||
| { | |||
| entries.add( null ); | |||
| } | |||
| if( entry instanceof Utf8CPInfo ) | |||
| { | |||
| Utf8CPInfo utf8Info = (Utf8CPInfo)entry; | |||
| utf8Indexes.put( utf8Info.getValue(), new Integer( index ) ); | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Read the constant pool from a class input stream. | |||
| * | |||
| * @param classStream the DataInputStream of a class file. | |||
| * @throws IOException if there is a problem reading the constant pool from | |||
| * the stream | |||
| */ | |||
| public void read( DataInputStream classStream ) | |||
| throws IOException | |||
| { | |||
| int numEntries = classStream.readUnsignedShort(); | |||
| for( int i = 1; i < numEntries; ) | |||
| { | |||
| ConstantPoolEntry nextEntry = ConstantPoolEntry.readEntry( classStream ); | |||
| i += nextEntry.getNumEntries(); | |||
| addEntry( nextEntry ); | |||
| } | |||
| } | |||
| /** | |||
| * Resolve the entries in the constant pool. Resolution of the constant pool | |||
| * involves transforming indexes to other constant pool entries into the | |||
| * actual data for that entry. | |||
| */ | |||
| public void resolve() | |||
| { | |||
| for( Iterator i = entries.iterator(); i.hasNext(); ) | |||
| { | |||
| ConstantPoolEntry poolInfo = (ConstantPoolEntry)i.next(); | |||
| if( poolInfo != null && !poolInfo.isResolved() ) | |||
| { | |||
| poolInfo.resolve( this ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Get the size of the constant pool. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public int size() | |||
| { | |||
| return entries.size(); | |||
| } | |||
| /** | |||
| * Dump the constant pool to a string. | |||
| * | |||
| * @return the constant pool entries as strings | |||
| */ | |||
| public String toString() | |||
| { | |||
| StringBuffer sb = new StringBuffer( "\n" ); | |||
| int size = entries.size(); | |||
| for( int i = 0; i < size; ++i ) | |||
| { | |||
| sb.append( "[" + i + "] = " + getEntry( i ) + "\n" ); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| } | |||
| @@ -1,243 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * An entry in the constant pool. This class contains a represenation of the | |||
| * constant pool entries. It is an abstract base class for all the different | |||
| * forms of constant pool entry. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @see ConstantPool | |||
| */ | |||
| public abstract class ConstantPoolEntry | |||
| { | |||
| /** | |||
| * Tag value for UTF8 entries. | |||
| */ | |||
| public final static int CONSTANT_Utf8 = 1; | |||
| /** | |||
| * Tag value for Integer entries. | |||
| */ | |||
| public final static int CONSTANT_Integer = 3; | |||
| /** | |||
| * Tag value for Float entries. | |||
| */ | |||
| public final static int CONSTANT_Float = 4; | |||
| /** | |||
| * Tag value for Long entries. | |||
| */ | |||
| public final static int CONSTANT_Long = 5; | |||
| /** | |||
| * Tag value for Double entries. | |||
| */ | |||
| public final static int CONSTANT_Double = 6; | |||
| /** | |||
| * Tag value for Class entries. | |||
| */ | |||
| public final static int CONSTANT_Class = 7; | |||
| /** | |||
| * Tag value for String entries. | |||
| */ | |||
| public final static int CONSTANT_String = 8; | |||
| /** | |||
| * Tag value for Field Reference entries. | |||
| */ | |||
| public final static int CONSTANT_FieldRef = 9; | |||
| /** | |||
| * Tag value for Method Reference entries. | |||
| */ | |||
| public final static int CONSTANT_MethodRef = 10; | |||
| /** | |||
| * Tag value for Interface Method Reference entries. | |||
| */ | |||
| public final static int CONSTANT_InterfaceMethodRef = 11; | |||
| /** | |||
| * Tag value for Name and Type entries. | |||
| */ | |||
| public final static int CONSTANT_NameAndType = 12; | |||
| /** | |||
| * The number of slots in the constant pool, occupied by this entry. | |||
| */ | |||
| private int numEntries; | |||
| /** | |||
| * A flag which indiciates if this entry has been resolved or not. | |||
| */ | |||
| private boolean resolved; | |||
| /** | |||
| * This entry's tag which identifies the type of this constant pool entry. | |||
| */ | |||
| private int tag; | |||
| /** | |||
| * Initialse the constant pool entry. | |||
| * | |||
| * @param tagValue the tag value which identifies which type of constant | |||
| * pool entry this is. | |||
| * @param entries the number of constant pool entry slots this entry | |||
| * occupies. | |||
| */ | |||
| public ConstantPoolEntry( int tagValue, int entries ) | |||
| { | |||
| tag = tagValue; | |||
| numEntries = entries; | |||
| resolved = false; | |||
| } | |||
| /** | |||
| * Read a constant pool entry from a stream. This is a factory method which | |||
| * reads a constant pool entry form a stream and returns the appropriate | |||
| * subclass for the entry. | |||
| * | |||
| * @param cpStream the stream from which the constant pool entry is to be | |||
| * read. | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| * @returns the appropriate ConstantPoolEntry subclass representing the | |||
| * constant pool entry from the stream. | |||
| * @throws IOExcception if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public static ConstantPoolEntry readEntry( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| ConstantPoolEntry cpInfo = null; | |||
| int cpTag = cpStream.readUnsignedByte(); | |||
| switch( cpTag ) | |||
| { | |||
| case CONSTANT_Utf8: | |||
| cpInfo = new Utf8CPInfo(); | |||
| break; | |||
| case CONSTANT_Integer: | |||
| cpInfo = new IntegerCPInfo(); | |||
| break; | |||
| case CONSTANT_Float: | |||
| cpInfo = new FloatCPInfo(); | |||
| break; | |||
| case CONSTANT_Long: | |||
| cpInfo = new LongCPInfo(); | |||
| break; | |||
| case CONSTANT_Double: | |||
| cpInfo = new DoubleCPInfo(); | |||
| break; | |||
| case CONSTANT_Class: | |||
| cpInfo = new ClassCPInfo(); | |||
| break; | |||
| case CONSTANT_String: | |||
| cpInfo = new StringCPInfo(); | |||
| break; | |||
| case CONSTANT_FieldRef: | |||
| cpInfo = new FieldRefCPInfo(); | |||
| break; | |||
| case CONSTANT_MethodRef: | |||
| cpInfo = new MethodRefCPInfo(); | |||
| break; | |||
| case CONSTANT_InterfaceMethodRef: | |||
| cpInfo = new InterfaceMethodRefCPInfo(); | |||
| break; | |||
| case CONSTANT_NameAndType: | |||
| cpInfo = new NameAndTypeCPInfo(); | |||
| break; | |||
| default: | |||
| throw new ClassFormatError( "Invalid Constant Pool entry Type " + cpTag ); | |||
| } | |||
| cpInfo.read( cpStream ); | |||
| return cpInfo; | |||
| } | |||
| /** | |||
| * Get the number of Constant Pool Entry slots within the constant pool | |||
| * occupied by this entry. | |||
| * | |||
| * @return the number of slots used. | |||
| */ | |||
| public final int getNumEntries() | |||
| { | |||
| return numEntries; | |||
| } | |||
| /** | |||
| * Get the Entry's type tag. | |||
| * | |||
| * @return The Tag value of this entry | |||
| */ | |||
| public int getTag() | |||
| { | |||
| return tag; | |||
| } | |||
| /** | |||
| * Indicates whether this entry has been resolved. In general a constant | |||
| * pool entry can reference another constant pool entry by its index value. | |||
| * Resolution involves replacing this index value with the constant pool | |||
| * entry at that index. | |||
| * | |||
| * @return true if this entry has been resolved. | |||
| */ | |||
| public boolean isResolved() | |||
| { | |||
| return resolved; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public abstract void read( DataInputStream cpStream ) | |||
| throws IOException; | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| resolved = true; | |||
| } | |||
| } | |||
| @@ -1,50 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * The constant pool entry subclass used to represent double constant values. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class DoubleCPInfo extends ConstantCPInfo | |||
| { | |||
| public DoubleCPInfo() | |||
| { | |||
| super( CONSTANT_Double, 2 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Double( cpStream.readDouble() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Double Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,111 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A FieldRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class FieldRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String fieldClassName; | |||
| private String fieldName; | |||
| private String fieldType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public FieldRefCPInfo() | |||
| { | |||
| super( CONSTANT_FieldRef, 1 ); | |||
| } | |||
| public String getFieldClassName() | |||
| { | |||
| return fieldClassName; | |||
| } | |||
| public String getFieldName() | |||
| { | |||
| return fieldName; | |||
| } | |||
| public String getFieldType() | |||
| { | |||
| return fieldType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo fieldClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| fieldClass.resolve( constantPool ); | |||
| fieldClassName = fieldClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| fieldName = nt.getName(); | |||
| fieldType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Field : Class = " + fieldClassName + ", name = " + fieldName + ", type = " + fieldType; | |||
| } | |||
| else | |||
| { | |||
| value = "Field : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A Float CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class FloatCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public FloatCPInfo() | |||
| { | |||
| super( CONSTANT_Float, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Float( cpStream.readFloat() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Float Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * An Integer CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class IntegerCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public IntegerCPInfo() | |||
| { | |||
| super( CONSTANT_Integer, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Integer( cpStream.readInt() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Integer Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,112 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A InterfaceMethodRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class InterfaceMethodRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String interfaceMethodClassName; | |||
| private String interfaceMethodName; | |||
| private String interfaceMethodType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public InterfaceMethodRefCPInfo() | |||
| { | |||
| super( CONSTANT_InterfaceMethodRef, 1 ); | |||
| } | |||
| public String getInterfaceMethodClassName() | |||
| { | |||
| return interfaceMethodClassName; | |||
| } | |||
| public String getInterfaceMethodName() | |||
| { | |||
| return interfaceMethodName; | |||
| } | |||
| public String getInterfaceMethodType() | |||
| { | |||
| return interfaceMethodType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo interfaceMethodClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| interfaceMethodClass.resolve( constantPool ); | |||
| interfaceMethodClassName = interfaceMethodClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| interfaceMethodName = nt.getName(); | |||
| interfaceMethodType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "InterfaceMethod : Class = " + interfaceMethodClassName + ", name = " + interfaceMethodName + ", type = " | |||
| + interfaceMethodType; | |||
| } | |||
| else | |||
| { | |||
| value = "InterfaceMethod : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A Long CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class LongCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public LongCPInfo() | |||
| { | |||
| super( CONSTANT_Long, 2 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Long( cpStream.readLong() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Long Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,111 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A MethodRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class MethodRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String methodClassName; | |||
| private String methodName; | |||
| private String methodType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public MethodRefCPInfo() | |||
| { | |||
| super( CONSTANT_MethodRef, 1 ); | |||
| } | |||
| public String getMethodClassName() | |||
| { | |||
| return methodClassName; | |||
| } | |||
| public String getMethodName() | |||
| { | |||
| return methodName; | |||
| } | |||
| public String getMethodType() | |||
| { | |||
| return methodType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo methodClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| methodClass.resolve( constantPool ); | |||
| methodClassName = methodClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| methodName = nt.getName(); | |||
| methodType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Method : Class = " + methodClassName + ", name = " + methodName + ", type = " + methodType; | |||
| } | |||
| else | |||
| { | |||
| value = "Method : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,95 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A NameAndType CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class NameAndTypeCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int descriptorIndex; | |||
| private String name; | |||
| private int nameIndex; | |||
| private String type; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public NameAndTypeCPInfo() | |||
| { | |||
| super( CONSTANT_NameAndType, 1 ); | |||
| } | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public String getType() | |||
| { | |||
| return type; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| nameIndex = cpStream.readUnsignedShort(); | |||
| descriptorIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| name = ( (Utf8CPInfo)constantPool.getEntry( nameIndex ) ).getValue(); | |||
| type = ( (Utf8CPInfo)constantPool.getEntry( descriptorIndex ) ).getValue(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Name = " + name + ", type = " + type; | |||
| } | |||
| else | |||
| { | |||
| value = "Name index = " + nameIndex + ", descriptor index = " + descriptorIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,71 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A String Constant Pool Entry. The String info contains an index into the | |||
| * constant pool where a UTF8 string is stored. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class StringCPInfo extends ConstantCPInfo | |||
| { | |||
| private int index; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public StringCPInfo() | |||
| { | |||
| super( CONSTANT_String, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| index = cpStream.readUnsignedShort(); | |||
| setValue( "unresolved" ); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| setValue( ( (Utf8CPInfo)constantPool.getEntry( index ) ).getValue() ); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "String Constant Pool Entry for " + getValue() + "[" + index + "]"; | |||
| } | |||
| } | |||
| @@ -1,60 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A UTF8 Constant Pool Entry. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class Utf8CPInfo extends ConstantPoolEntry | |||
| { | |||
| private String value; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public Utf8CPInfo() | |||
| { | |||
| super( CONSTANT_Utf8, 1 ); | |||
| } | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| value = cpStream.readUTF(); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "UTF8 Value = " + value; | |||
| } | |||
| } | |||
| @@ -1,118 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ClassCPInfo; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool; | |||
| import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPoolEntry; | |||
| /** | |||
| * A ClassFile object stores information about a Java class. The class may be | |||
| * read from a DataInputStream.and written to a DataOutputStream. These are | |||
| * usually streams from a Java class file or a class file component of a Jar | |||
| * file. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassFile | |||
| { | |||
| /** | |||
| * The Magic Value that marks the start of a Java class file | |||
| */ | |||
| private final static int CLASS_MAGIC = 0xCAFEBABE; | |||
| /** | |||
| * The class name for this class. | |||
| */ | |||
| private String className; | |||
| /** | |||
| * This class' constant pool. | |||
| */ | |||
| private ConstantPool constantPool; | |||
| /** | |||
| * Get the classes which this class references. | |||
| * | |||
| * @return The ClassRefs value | |||
| */ | |||
| public ArrayList getClassRefs() | |||
| { | |||
| ArrayList classRefs = new ArrayList(); | |||
| for( int i = 0; i < constantPool.size(); ++i ) | |||
| { | |||
| ConstantPoolEntry entry = constantPool.getEntry( i ); | |||
| if( entry != null && entry.getTag() == ConstantPoolEntry.CONSTANT_Class ) | |||
| { | |||
| ClassCPInfo classEntry = (ClassCPInfo)entry; | |||
| if( !classEntry.getClassName().equals( className ) ) | |||
| { | |||
| classRefs.add( ClassFileUtils.convertSlashName( classEntry.getClassName() ) ); | |||
| } | |||
| } | |||
| } | |||
| return classRefs; | |||
| } | |||
| /** | |||
| * Get the class' fully qualified name in dot format. | |||
| * | |||
| * @return the class name in dot format (eg. java.lang.Object) | |||
| */ | |||
| public String getFullClassName() | |||
| { | |||
| return ClassFileUtils.convertSlashName( className ); | |||
| } | |||
| /** | |||
| * Read the class from a data stream. This method takes an InputStream as | |||
| * input and parses the class from the stream. <p> | |||
| * | |||
| * | |||
| * | |||
| * @param stream an InputStream from which the class will be read | |||
| * @throws IOException if there is a problem reading from the given stream. | |||
| * @throws ClassFormatError if the class cannot be parsed correctly | |||
| */ | |||
| public void read( InputStream stream ) | |||
| throws IOException, ClassFormatError | |||
| { | |||
| DataInputStream classStream = new DataInputStream( stream ); | |||
| if( classStream.readInt() != CLASS_MAGIC ) | |||
| { | |||
| throw new ClassFormatError( "No Magic Code Found - probably not a Java class file." ); | |||
| } | |||
| // right we have a good looking class file. | |||
| int minorVersion = classStream.readUnsignedShort(); | |||
| int majorVersion = classStream.readUnsignedShort(); | |||
| // read the constant pool in and resolve it | |||
| constantPool = new ConstantPool(); | |||
| constantPool.read( classStream ); | |||
| constantPool.resolve(); | |||
| int accessFlags = classStream.readUnsignedShort(); | |||
| int thisClassIndex = classStream.readUnsignedShort(); | |||
| int superClassIndex = classStream.readUnsignedShort(); | |||
| className = ( (ClassCPInfo)constantPool.getEntry( thisClassIndex ) ).getClassName(); | |||
| } | |||
| } | |||
| @@ -1,14 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| public interface ClassFileIterator | |||
| { | |||
| ClassFile getNextClassFile(); | |||
| } | |||
| @@ -1,44 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| /** | |||
| * Utility class file routines. This class porovides a number of static utility | |||
| * methods to convert between the formats used in the Java class file format and | |||
| * those commonly used in Java programming. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassFileUtils | |||
| { | |||
| /** | |||
| * Convert a class name from java source file dot notation to class file | |||
| * slash notation.. | |||
| * | |||
| * @param dotName the class name in dot notation (eg. java.lang.Object). | |||
| * @return the class name in slash notation (eg. java/lang/Object). | |||
| */ | |||
| public static String convertDotName( String dotName ) | |||
| { | |||
| return dotName.replace( '.', '/' ); | |||
| } | |||
| /** | |||
| * Convert a class name from class file slash notation to java source file | |||
| * dot notation. | |||
| * | |||
| * @param name Description of Parameter | |||
| * @return the class name in dot notation (eg. java.lang.Object). | |||
| */ | |||
| public static String convertSlashName( String name ) | |||
| { | |||
| return name.replace( '\\', '.' ).replace( '/', '.' ); | |||
| } | |||
| } | |||
| @@ -1,753 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileReader; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.io.PrintWriter; | |||
| import java.net.URL; | |||
| import java.net.URLClassLoader; | |||
| import java.util.ArrayList; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.ant.taskdefs.MatchingTask; | |||
| import org.apache.tools.ant.types.DirectoryScanner; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.types.PathUtil; | |||
| /** | |||
| * Generate a dependency file for a given set of classes | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class Depend extends MatchingTask | |||
| { | |||
| /** | |||
| * constants used with the cache file | |||
| */ | |||
| private final static String CACHE_FILE_NAME = "dependencies.txt"; | |||
| private final static String CLASSNAME_PREPEND = "||:"; | |||
| /** | |||
| * indicates that the dependency relationships should be extended beyond | |||
| * direct dependencies to include all classes. So if A directly affects B | |||
| * abd B directly affects C, then A indirectly affects C. | |||
| */ | |||
| private boolean closure = false; | |||
| /** | |||
| * Flag which controls whether the reversed dependencies should be dumped to | |||
| * the log | |||
| */ | |||
| private boolean dump = false; | |||
| /** | |||
| * A map which gives for every class a list of te class which it affects. | |||
| */ | |||
| private Hashtable affectedClassMap; | |||
| /** | |||
| * The directory which contains the dependency cache. | |||
| */ | |||
| private File cache; | |||
| /** | |||
| * A map which gives information about a class | |||
| */ | |||
| private Hashtable classFileInfoMap; | |||
| /** | |||
| * A map which gives the list of jars and classes from the classpath that a | |||
| * class depends upon | |||
| */ | |||
| private Hashtable classpathDependencies; | |||
| /** | |||
| * The classpath to look for additional dependencies | |||
| */ | |||
| private Path dependClasspath; | |||
| /** | |||
| * The path where compiled class files exist. | |||
| */ | |||
| private Path destPath; | |||
| /** | |||
| * The list of classes which are out of date. | |||
| */ | |||
| private Hashtable outOfDateClasses; | |||
| /** | |||
| * The path where source files exist | |||
| */ | |||
| private Path srcPath; | |||
| public void setCache( File cache ) | |||
| { | |||
| this.cache = cache; | |||
| } | |||
| /** | |||
| * Set the classpath to be used for this dependency check. | |||
| * | |||
| * @param classpath The new Classpath value | |||
| */ | |||
| public void setClasspath( Path classpath ) | |||
| throws TaskException | |||
| { | |||
| if( dependClasspath == null ) | |||
| { | |||
| dependClasspath = classpath; | |||
| } | |||
| else | |||
| { | |||
| dependClasspath.append( classpath ); | |||
| } | |||
| } | |||
| public void setClosure( boolean closure ) | |||
| { | |||
| this.closure = closure; | |||
| } | |||
| /** | |||
| * Set the destination directory where the compiled java files exist. | |||
| * | |||
| * @param destPath The new DestDir value | |||
| */ | |||
| public void setDestDir( Path destPath ) | |||
| { | |||
| this.destPath = destPath; | |||
| } | |||
| /** | |||
| * Flag to indicate whether the reverse dependency list should be dumped to | |||
| * debug | |||
| * | |||
| * @param dump The new Dump value | |||
| */ | |||
| public void setDump( boolean dump ) | |||
| { | |||
| this.dump = dump; | |||
| } | |||
| /** | |||
| * Set the source dirs to find the source Java files. | |||
| * | |||
| * @param srcPath The new Srcdir value | |||
| */ | |||
| public void setSrcdir( Path srcPath ) | |||
| { | |||
| this.srcPath = srcPath; | |||
| } | |||
| /** | |||
| * Gets the classpath to be used for this dependency check. | |||
| * | |||
| * @return The Classpath value | |||
| */ | |||
| public Path getClasspath() | |||
| { | |||
| return dependClasspath; | |||
| } | |||
| /** | |||
| * Creates a nested classpath element. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public Path createClasspath() | |||
| throws TaskException | |||
| { | |||
| if( dependClasspath == null ) | |||
| { | |||
| dependClasspath = new Path(); | |||
| } | |||
| Path path1 = dependClasspath; | |||
| final Path path = new Path(); | |||
| path1.addPath( path ); | |||
| return path; | |||
| } | |||
| /** | |||
| * Does the work. | |||
| * | |||
| * @exception TaskException Thrown in unrecovrable error. | |||
| */ | |||
| public void execute() | |||
| throws TaskException | |||
| { | |||
| try | |||
| { | |||
| long start = System.currentTimeMillis(); | |||
| String[] srcPathList = srcPath.list(); | |||
| if( srcPathList.length == 0 ) | |||
| { | |||
| throw new TaskException( "srcdir attribute must be set!" ); | |||
| } | |||
| if( destPath == null ) | |||
| { | |||
| destPath = srcPath; | |||
| } | |||
| if( cache != null && cache.exists() && !cache.isDirectory() ) | |||
| { | |||
| throw new TaskException( "The cache, if specified, must point to a directory" ); | |||
| } | |||
| if( cache != null && !cache.exists() ) | |||
| { | |||
| cache.mkdirs(); | |||
| } | |||
| determineDependencies(); | |||
| if( dump ) | |||
| { | |||
| getLogger().debug( "Reverse Dependency Dump for " + affectedClassMap.size() + " classes:" ); | |||
| for( Enumeration e = affectedClassMap.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| getLogger().debug( " Class " + className + " affects:" ); | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( className ); | |||
| for( Enumeration e2 = affectedClasses.keys(); e2.hasMoreElements(); ) | |||
| { | |||
| String affectedClass = (String)e2.nextElement(); | |||
| ClassFileInfo info = (ClassFileInfo)affectedClasses.get( affectedClass ); | |||
| getLogger().debug( " " + affectedClass + " in " + info.absoluteFile.getPath() ); | |||
| } | |||
| } | |||
| if( classpathDependencies != null ) | |||
| { | |||
| getLogger().debug( "Classpath file dependencies (Forward):" ); | |||
| for( Enumeration e = classpathDependencies.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| getLogger().debug( " Class " + className + " depends on:" ); | |||
| Hashtable dependencies = (Hashtable)classpathDependencies.get( className ); | |||
| for( Enumeration e2 = dependencies.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| File classpathFile = (File)e2.nextElement(); | |||
| getLogger().debug( " " + classpathFile.getPath() ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // we now need to scan for out of date files. When we have the list | |||
| // we go through and delete all class files which are affected by these files. | |||
| outOfDateClasses = new Hashtable(); | |||
| for( int i = 0; i < srcPathList.length; i++ ) | |||
| { | |||
| File srcDir = (File)resolveFile( srcPathList[ i ] ); | |||
| if( srcDir.exists() ) | |||
| { | |||
| DirectoryScanner ds = this.getDirectoryScanner( srcDir ); | |||
| String[] files = ds.getIncludedFiles(); | |||
| scanDir( srcDir, files ); | |||
| } | |||
| } | |||
| // now check classpath file dependencies | |||
| if( classpathDependencies != null ) | |||
| { | |||
| for( Enumeration e = classpathDependencies.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| if( !outOfDateClasses.containsKey( className ) ) | |||
| { | |||
| ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| // if we have no info about the class - it may have been deleted already and we | |||
| // are using cached info. | |||
| if( info != null ) | |||
| { | |||
| Hashtable dependencies = (Hashtable)classpathDependencies.get( className ); | |||
| for( Enumeration e2 = dependencies.elements(); e2.hasMoreElements(); ) | |||
| { | |||
| File classpathFile = (File)e2.nextElement(); | |||
| if( classpathFile.lastModified() > info.absoluteFile.lastModified() ) | |||
| { | |||
| getLogger().debug( "Class " + className + " is out of date with respect to " + classpathFile ); | |||
| outOfDateClasses.put( className, className ); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // we now have a complete list of classes which are out of date | |||
| // We scan through the affected classes, deleting any affected classes. | |||
| int count = deleteAllAffectedFiles(); | |||
| long duration = ( System.currentTimeMillis() - start ) / 1000; | |||
| getLogger().info( "Deleted " + count + " out of date files in " + duration + " seconds" ); | |||
| } | |||
| catch( Exception e ) | |||
| { | |||
| throw new TaskException( "Error", e ); | |||
| } | |||
| } | |||
| /** | |||
| * Scans the directory looking for source files that are newer than their | |||
| * class files. The results are returned in the class variable compileList | |||
| * | |||
| * @param srcDir Description of Parameter | |||
| * @param files Description of Parameter | |||
| */ | |||
| protected void scanDir( File srcDir, String files[] ) | |||
| { | |||
| long now = System.currentTimeMillis(); | |||
| for( int i = 0; i < files.length; i++ ) | |||
| { | |||
| File srcFile = new File( srcDir, files[ i ] ); | |||
| if( files[ i ].endsWith( ".java" ) ) | |||
| { | |||
| String filePath = srcFile.getPath(); | |||
| String className = filePath.substring( srcDir.getPath().length() + 1, | |||
| filePath.length() - ".java".length() ); | |||
| className = ClassFileUtils.convertSlashName( className ); | |||
| ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| if( info == null ) | |||
| { | |||
| // there was no class file. add this class to the list | |||
| outOfDateClasses.put( className, className ); | |||
| } | |||
| else | |||
| { | |||
| if( srcFile.lastModified() > info.absoluteFile.lastModified() ) | |||
| { | |||
| outOfDateClasses.put( className, className ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Get the list of class files we are going to analyse. | |||
| * | |||
| * @param classLocations a path structure containing all the directories | |||
| * where classes can be found. | |||
| * @return a vector containing the classes to analyse. | |||
| */ | |||
| private ArrayList getClassFiles( Path classLocations ) | |||
| throws TaskException | |||
| { | |||
| // break the classLocations into its components. | |||
| String[] classLocationsList = classLocations.list(); | |||
| ArrayList classFileList = new ArrayList(); | |||
| for( int i = 0; i < classLocationsList.length; ++i ) | |||
| { | |||
| File dir = new File( classLocationsList[ i ] ); | |||
| if( dir.isDirectory() ) | |||
| { | |||
| addClassFiles( classFileList, dir, dir ); | |||
| } | |||
| } | |||
| return classFileList; | |||
| } | |||
| /** | |||
| * Add the list of class files from the given directory to the class file | |||
| * vector, including any subdirectories. | |||
| * | |||
| * @param classFileList The feature to be added to the ClassFiles attribute | |||
| * @param dir The feature to be added to the ClassFiles attribute | |||
| * @param root The feature to be added to the ClassFiles attribute | |||
| */ | |||
| private void addClassFiles( ArrayList classFileList, File dir, File root ) | |||
| { | |||
| String[] filesInDir = dir.list(); | |||
| if( filesInDir != null ) | |||
| { | |||
| int length = filesInDir.length; | |||
| for( int i = 0; i < length; ++i ) | |||
| { | |||
| File file = new File( dir, filesInDir[ i ] ); | |||
| if( file.isDirectory() ) | |||
| { | |||
| addClassFiles( classFileList, file, root ); | |||
| } | |||
| else if( file.getName().endsWith( ".class" ) ) | |||
| { | |||
| ClassFileInfo info = new ClassFileInfo(); | |||
| info.absoluteFile = file; | |||
| info.relativeName = file.getPath().substring( root.getPath().length() + 1, | |||
| file.getPath().length() - 6 ); | |||
| info.className = ClassFileUtils.convertSlashName( info.relativeName ); | |||
| classFileList.add( info ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private int deleteAffectedFiles( String className ) | |||
| { | |||
| int count = 0; | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( className ); | |||
| if( affectedClasses != null ) | |||
| { | |||
| for( Enumeration e = affectedClasses.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String affectedClassName = (String)e.nextElement(); | |||
| ClassFileInfo affectedClassInfo = (ClassFileInfo)affectedClasses.get( affectedClassName ); | |||
| if( affectedClassInfo.absoluteFile.exists() ) | |||
| { | |||
| getLogger().debug( "Deleting file " + affectedClassInfo.absoluteFile.getPath() + " since " + className + " out of date" ); | |||
| affectedClassInfo.absoluteFile.delete(); | |||
| count++; | |||
| if( closure ) | |||
| { | |||
| count += deleteAffectedFiles( affectedClassName ); | |||
| } | |||
| else | |||
| { | |||
| // without closure we may delete an inner class but not the | |||
| // top level class which would not trigger a recompile. | |||
| if( affectedClassName.indexOf( "$" ) != -1 ) | |||
| { | |||
| // need to delete the main class | |||
| String topLevelClassName | |||
| = affectedClassName.substring( 0, affectedClassName.indexOf( "$" ) ); | |||
| getLogger().debug( "Top level class = " + topLevelClassName ); | |||
| ClassFileInfo topLevelClassInfo | |||
| = (ClassFileInfo)classFileInfoMap.get( topLevelClassName ); | |||
| if( topLevelClassInfo != null && | |||
| topLevelClassInfo.absoluteFile.exists() ) | |||
| { | |||
| getLogger().debug( "Deleting file " + topLevelClassInfo.absoluteFile.getPath() + " since " + "one of its inner classes was removed" ); | |||
| topLevelClassInfo.absoluteFile.delete(); | |||
| count++; | |||
| if( closure ) | |||
| { | |||
| count += deleteAffectedFiles( topLevelClassName ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| private int deleteAllAffectedFiles() | |||
| { | |||
| int count = 0; | |||
| for( Enumeration e = outOfDateClasses.elements(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| count += deleteAffectedFiles( className ); | |||
| ClassFileInfo classInfo = (ClassFileInfo)classFileInfoMap.get( className ); | |||
| if( classInfo != null && classInfo.absoluteFile.exists() ) | |||
| { | |||
| classInfo.absoluteFile.delete(); | |||
| count++; | |||
| } | |||
| } | |||
| return count; | |||
| } | |||
| /** | |||
| * Determine the dependencies between classes. Class dependencies are | |||
| * determined by examining the class references in a class file to other | |||
| * classes | |||
| * | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private void determineDependencies() | |||
| throws IOException, TaskException | |||
| { | |||
| affectedClassMap = new Hashtable(); | |||
| classFileInfoMap = new Hashtable(); | |||
| boolean cacheDirty = false; | |||
| Hashtable dependencyMap = new Hashtable(); | |||
| File depCacheFile = null; | |||
| boolean depCacheFileExists = true; | |||
| long depCacheFileLastModified = Long.MAX_VALUE; | |||
| // read the dependency cache from the disk | |||
| if( cache != null ) | |||
| { | |||
| dependencyMap = readCachedDependencies(); | |||
| depCacheFile = new File( cache, CACHE_FILE_NAME ); | |||
| depCacheFileExists = depCacheFile.exists(); | |||
| depCacheFileLastModified = depCacheFile.lastModified(); | |||
| } | |||
| for( Iterator e = getClassFiles( destPath ).iterator(); e.hasNext(); ) | |||
| { | |||
| ClassFileInfo info = (ClassFileInfo)e.next(); | |||
| getLogger().debug( "Adding class info for " + info.className ); | |||
| classFileInfoMap.put( info.className, info ); | |||
| ArrayList dependencyList = null; | |||
| if( cache != null ) | |||
| { | |||
| // try to read the dependency info from the map if it is not out of date | |||
| if( depCacheFileExists && depCacheFileLastModified > info.absoluteFile.lastModified() ) | |||
| { | |||
| // depFile exists and is newer than the class file | |||
| // need to get dependency list from the map. | |||
| dependencyList = (ArrayList)dependencyMap.get( info.className ); | |||
| } | |||
| } | |||
| if( dependencyList == null ) | |||
| { | |||
| // not cached - so need to read directly from the class file | |||
| FileInputStream inFileStream = null; | |||
| try | |||
| { | |||
| inFileStream = new FileInputStream( info.absoluteFile ); | |||
| ClassFile classFile = new ClassFile(); | |||
| classFile.read( inFileStream ); | |||
| dependencyList = classFile.getClassRefs(); | |||
| if( dependencyList != null ) | |||
| { | |||
| cacheDirty = true; | |||
| dependencyMap.put( info.className, dependencyList ); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( inFileStream != null ) | |||
| { | |||
| inFileStream.close(); | |||
| } | |||
| } | |||
| } | |||
| // This class depends on each class in the dependency list. For each | |||
| // one of those, add this class into their affected classes list | |||
| for( Iterator depEnum = dependencyList.iterator(); depEnum.hasNext(); ) | |||
| { | |||
| String dependentClass = (String)depEnum.next(); | |||
| Hashtable affectedClasses = (Hashtable)affectedClassMap.get( dependentClass ); | |||
| if( affectedClasses == null ) | |||
| { | |||
| affectedClasses = new Hashtable(); | |||
| affectedClassMap.put( dependentClass, affectedClasses ); | |||
| } | |||
| affectedClasses.put( info.className, info ); | |||
| } | |||
| } | |||
| classpathDependencies = null; | |||
| if( dependClasspath != null ) | |||
| { | |||
| // now determine which jars each class depends upon | |||
| classpathDependencies = new Hashtable(); | |||
| final URL[] urls = PathUtil.toURLs( dependClasspath ); | |||
| final ClassLoader classLoader = new URLClassLoader( urls ); | |||
| Hashtable classpathFileCache = new Hashtable(); | |||
| Object nullFileMarker = new Object(); | |||
| for( Enumeration e = dependencyMap.keys(); e.hasMoreElements(); ) | |||
| { | |||
| String className = (String)e.nextElement(); | |||
| ArrayList dependencyList = (ArrayList)dependencyMap.get( className ); | |||
| Hashtable dependencies = new Hashtable(); | |||
| classpathDependencies.put( className, dependencies ); | |||
| for( Iterator e2 = dependencyList.iterator(); e2.hasNext(); ) | |||
| { | |||
| String dependency = (String)e2.next(); | |||
| Object classpathFileObject = classpathFileCache.get( dependency ); | |||
| if( classpathFileObject == null ) | |||
| { | |||
| classpathFileObject = nullFileMarker; | |||
| if( !dependency.startsWith( "java." ) && !dependency.startsWith( "javax." ) ) | |||
| { | |||
| final String name = dependency.replace( '.', '/' ) + ".class"; | |||
| URL classURL = classLoader.getResource( name ); | |||
| if( classURL != null ) | |||
| { | |||
| if( classURL.getProtocol().equals( "jar" ) ) | |||
| { | |||
| String jarFilePath = classURL.getFile(); | |||
| if( jarFilePath.startsWith( "file:" ) ) | |||
| { | |||
| int classMarker = jarFilePath.indexOf( '!' ); | |||
| jarFilePath = jarFilePath.substring( 5, classMarker ); | |||
| } | |||
| classpathFileObject = new File( jarFilePath ); | |||
| } | |||
| else if( classURL.getProtocol().equals( "file" ) ) | |||
| { | |||
| String classFilePath = classURL.getFile(); | |||
| classpathFileObject = new File( classFilePath ); | |||
| } | |||
| getLogger().debug( "Class " + className + " depends on " + classpathFileObject + " due to " + dependency ); | |||
| } | |||
| } | |||
| classpathFileCache.put( dependency, classpathFileObject ); | |||
| } | |||
| if( classpathFileObject != null && classpathFileObject != nullFileMarker ) | |||
| { | |||
| // we need to add this jar to the list for this class. | |||
| File jarFile = (File)classpathFileObject; | |||
| dependencies.put( jarFile, jarFile ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // write the dependency cache to the disk | |||
| if( cache != null && cacheDirty ) | |||
| { | |||
| writeCachedDependencies( dependencyMap ); | |||
| } | |||
| } | |||
| /** | |||
| * Read the dependencies from cache file | |||
| * | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private Hashtable readCachedDependencies() | |||
| throws IOException | |||
| { | |||
| Hashtable dependencyMap = new Hashtable(); | |||
| if( cache != null ) | |||
| { | |||
| File depFile = new File( cache, CACHE_FILE_NAME ); | |||
| BufferedReader in = null; | |||
| if( depFile.exists() ) | |||
| { | |||
| try | |||
| { | |||
| in = new BufferedReader( new FileReader( depFile ) ); | |||
| String line = null; | |||
| ArrayList dependencyList = null; | |||
| String className = null; | |||
| int prependLength = CLASSNAME_PREPEND.length(); | |||
| while( ( line = in.readLine() ) != null ) | |||
| { | |||
| if( line.startsWith( CLASSNAME_PREPEND ) ) | |||
| { | |||
| dependencyList = new ArrayList(); | |||
| className = line.substring( prependLength ); | |||
| dependencyMap.put( className, dependencyList ); | |||
| } | |||
| else | |||
| { | |||
| dependencyList.add( line ); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( in != null ) | |||
| { | |||
| in.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return dependencyMap; | |||
| } | |||
| /** | |||
| * Write the dependencies to cache file | |||
| * | |||
| * @param dependencyMap Description of Parameter | |||
| * @exception IOException Description of Exception | |||
| */ | |||
| private void writeCachedDependencies( Hashtable dependencyMap ) | |||
| throws IOException | |||
| { | |||
| if( cache != null ) | |||
| { | |||
| PrintWriter pw = null; | |||
| try | |||
| { | |||
| cache.mkdirs(); | |||
| File depFile = new File( cache, CACHE_FILE_NAME ); | |||
| pw = new PrintWriter( new FileWriter( depFile ) ); | |||
| for( Enumeration deps = dependencyMap.keys(); deps.hasMoreElements(); ) | |||
| { | |||
| String className = (String)deps.nextElement(); | |||
| pw.println( CLASSNAME_PREPEND + className ); | |||
| ArrayList dependencyList = (ArrayList)dependencyMap.get( className ); | |||
| int size = dependencyList.size(); | |||
| for( int x = 0; x < size; x++ ) | |||
| { | |||
| pw.println( dependencyList.get( x ) ); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| if( pw != null ) | |||
| { | |||
| pw.close(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * A class (struct) user to manage information about a class | |||
| * | |||
| * @author RT | |||
| */ | |||
| private static class ClassFileInfo | |||
| { | |||
| /** | |||
| * The file where the class file is stored in the file system | |||
| */ | |||
| public File absoluteFile; | |||
| /** | |||
| * The Java class name of this class | |||
| */ | |||
| public String className; | |||
| /** | |||
| * The location of the file relative to its base directory - the root of | |||
| * the package namespace | |||
| */ | |||
| public String relativeName; | |||
| } | |||
| } | |||
| @@ -1,186 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.util.ArrayList; | |||
| import java.util.Iterator; | |||
| import java.util.Stack; | |||
| /** | |||
| * An iterator which iterates through the contents of a java directory. The | |||
| * iterator should be created with the directory at the root of the Java | |||
| * namespace. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class DirectoryIterator implements ClassFileIterator | |||
| { | |||
| /** | |||
| * The length of the root directory. This is used to remove the root | |||
| * directory from full paths. | |||
| */ | |||
| int rootLength; | |||
| /** | |||
| * The current directory iterator. As directories encounter lower level | |||
| * directories, the current iterator is pushed onto the iterator stack and a | |||
| * new iterator over the sub directory becomes the current directory. This | |||
| * implements a depth first traversal of the directory namespace. | |||
| */ | |||
| private Iterator currentEnum; | |||
| /** | |||
| * This is a stack of current iterators supporting the depth first traversal | |||
| * of the directory tree. | |||
| */ | |||
| private Stack enumStack; | |||
| /** | |||
| * Creates a directory iterator. The directory iterator is created to scan | |||
| * the root directory. If the changeInto flag is given, then the entries | |||
| * returned will be relative to this directory and not the current | |||
| * directory. | |||
| * | |||
| * @param rootDirectory the root if the directory namespace which is to be | |||
| * iterated over | |||
| * @param changeInto if true then the returned entries will be relative to | |||
| * the rootDirectory and not the current directory. | |||
| * @exception IOException Description of Exception | |||
| * @throws IOException if there is a problem reading the directory | |||
| * information. | |||
| */ | |||
| public DirectoryIterator( File rootDirectory, boolean changeInto ) | |||
| throws IOException | |||
| { | |||
| super(); | |||
| enumStack = new Stack(); | |||
| if( rootDirectory.isAbsolute() || changeInto ) | |||
| { | |||
| rootLength = rootDirectory.getPath().length() + 1; | |||
| } | |||
| else | |||
| { | |||
| rootLength = 0; | |||
| } | |||
| ArrayList filesInRoot = getDirectoryEntries( rootDirectory ); | |||
| currentEnum = filesInRoot.iterator(); | |||
| } | |||
| /** | |||
| * Template method to allow subclasses to supply elements for the iteration. | |||
| * The directory iterator maintains a stack of iterators covering each level | |||
| * in the directory hierarchy. The current iterator covers the current | |||
| * directory being scanned. If the next entry in that directory is a | |||
| * subdirectory, the current iterator is pushed onto the stack and a new | |||
| * iterator is created for the subdirectory. If the entry is a file, it is | |||
| * returned as the next element and the iterator remains valid. If there are | |||
| * no more entries in the current directory, the topmost iterator on the | |||
| * statck is popped off to become the current iterator. | |||
| * | |||
| * @return the next ClassFile in the iteration. | |||
| */ | |||
| public ClassFile getNextClassFile() | |||
| { | |||
| ClassFile next = null; | |||
| try | |||
| { | |||
| while( next == null ) | |||
| { | |||
| if( currentEnum.hasNext() ) | |||
| { | |||
| File element = (File)currentEnum.next(); | |||
| if( element.isDirectory() ) | |||
| { | |||
| // push the current iterator onto the stack and then | |||
| // iterate through this directory. | |||
| enumStack.push( currentEnum ); | |||
| ArrayList files = getDirectoryEntries( element ); | |||
| currentEnum = files.iterator(); | |||
| } | |||
| else | |||
| { | |||
| // we have a file. create a stream for it | |||
| FileInputStream inFileStream = new FileInputStream( element ); | |||
| if( element.getName().endsWith( ".class" ) ) | |||
| { | |||
| // create a data input stream from the jar input stream | |||
| ClassFile javaClass = new ClassFile(); | |||
| javaClass.read( inFileStream ); | |||
| next = javaClass; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // this iterator is exhausted. Can we pop one off the stack | |||
| if( enumStack.empty() ) | |||
| { | |||
| break; | |||
| } | |||
| else | |||
| { | |||
| currentEnum = (Iterator)enumStack.pop(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| next = null; | |||
| } | |||
| return next; | |||
| } | |||
| /** | |||
| * Get a vector covering all the entries (files and subdirectories in a | |||
| * directory). | |||
| * | |||
| * @param directory the directory to be scanned. | |||
| * @return a vector containing File objects for each entry in the directory. | |||
| */ | |||
| private ArrayList getDirectoryEntries( File directory ) | |||
| { | |||
| ArrayList files = new ArrayList(); | |||
| // File[] filesInDir = directory.listFiles(); | |||
| String[] filesInDir = directory.list(); | |||
| if( filesInDir != null ) | |||
| { | |||
| int length = filesInDir.length; | |||
| for( int i = 0; i < length; ++i ) | |||
| { | |||
| files.add( new File( directory, filesInDir[ i ] ) ); | |||
| } | |||
| } | |||
| return files; | |||
| } | |||
| } | |||
| @@ -1,95 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipInputStream; | |||
| /** | |||
| * A class file iterator which iterates through the contents of a Java jar file. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class JarFileIterator implements ClassFileIterator | |||
| { | |||
| private ZipInputStream jarStream; | |||
| public JarFileIterator( InputStream stream ) | |||
| throws IOException | |||
| { | |||
| super(); | |||
| jarStream = new ZipInputStream( stream ); | |||
| } | |||
| public ClassFile getNextClassFile() | |||
| { | |||
| ZipEntry jarEntry; | |||
| ClassFile next = null; | |||
| try | |||
| { | |||
| jarEntry = jarStream.getNextEntry(); | |||
| while( next == null && jarEntry != null ) | |||
| { | |||
| String entryName = jarEntry.getName(); | |||
| if( !jarEntry.isDirectory() && entryName.endsWith( ".class" ) ) | |||
| { | |||
| // create a data input stream from the jar input stream | |||
| ClassFile javaClass = new ClassFile(); | |||
| javaClass.read( jarStream ); | |||
| next = javaClass; | |||
| } | |||
| else | |||
| { | |||
| jarEntry = jarStream.getNextEntry(); | |||
| } | |||
| } | |||
| } | |||
| catch( IOException e ) | |||
| { | |||
| String message = e.getMessage(); | |||
| String text = e.getClass().getName(); | |||
| if( message != null ) | |||
| { | |||
| text += ": " + message; | |||
| } | |||
| throw new RuntimeException( "Problem reading JAR file: " + text ); | |||
| } | |||
| return next; | |||
| } | |||
| private byte[] getEntryBytes( InputStream stream ) | |||
| throws IOException | |||
| { | |||
| byte[] buffer = new byte[ 8192 ]; | |||
| ByteArrayOutputStream baos = new ByteArrayOutputStream( 2048 ); | |||
| int n; | |||
| while( ( n = stream.read( buffer, 0, buffer.length ) ) != -1 ) | |||
| { | |||
| baos.write( buffer, 0, n ); | |||
| } | |||
| return baos.toByteArray(); | |||
| } | |||
| } | |||
| @@ -1,89 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * The constant pool entry which stores class information. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class ClassCPInfo extends ConstantPoolEntry | |||
| { | |||
| /** | |||
| * The class' name. This will be only valid if the entry has been resolved | |||
| * against the constant pool. | |||
| */ | |||
| private String className; | |||
| /** | |||
| * The index into the constant pool where this class' name is stored. If the | |||
| * class name is changed, this entry is invalid until this entry is | |||
| * connected to a constant pool. | |||
| */ | |||
| private int index; | |||
| /** | |||
| * Constructor. Sets the tag value for this entry to type Class | |||
| */ | |||
| public ClassCPInfo() | |||
| { | |||
| super( CONSTANT_Class, 1 ); | |||
| } | |||
| /** | |||
| * Get the class name of this entry. | |||
| * | |||
| * @return the class' name. | |||
| */ | |||
| public String getClassName() | |||
| { | |||
| return className; | |||
| } | |||
| /** | |||
| * Read the entry from a stream. | |||
| * | |||
| * @param cpStream the stream containing the constant pool entry to be read. | |||
| * @exception IOException thrown if there is a problem reading the entry | |||
| * from the stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| index = cpStream.readUnsignedShort(); | |||
| className = "unresolved"; | |||
| } | |||
| /** | |||
| * Resolve this class info against the given constant pool. | |||
| * | |||
| * @param constantPool the constant pool with which to resolve the class. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| className = ( (Utf8CPInfo)constantPool.getEntry( index ) ).getValue(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Generate a string readable version of this entry | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Class Constant Pool Entry for " + className + "[" + index + "]"; | |||
| } | |||
| } | |||
| @@ -1,57 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| /** | |||
| * A Constant Pool entry which represents a constant value. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public abstract class ConstantCPInfo extends ConstantPoolEntry | |||
| { | |||
| /** | |||
| * The entry's untyped value. Each subclass interprets the constant value | |||
| * based on the subclass's type. The value here must be compatible. | |||
| */ | |||
| private Object value; | |||
| /** | |||
| * Initialise the constant entry. | |||
| * | |||
| * @param tagValue the constant pool entry type to be used. | |||
| * @param entries the number of constant pool entry slots occupied by this | |||
| * entry. | |||
| */ | |||
| protected ConstantCPInfo( int tagValue, int entries ) | |||
| { | |||
| super( tagValue, entries ); | |||
| } | |||
| /** | |||
| * Set the constant value. | |||
| * | |||
| * @param newValue the new untyped value of this constant. | |||
| */ | |||
| public void setValue( Object newValue ) | |||
| { | |||
| value = newValue; | |||
| } | |||
| /** | |||
| * Get the value of the constant. | |||
| * | |||
| * @return the value of the constant (untyped). | |||
| */ | |||
| public Object getValue() | |||
| { | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,374 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| import java.util.ArrayList; | |||
| import java.util.Hashtable; | |||
| import java.util.Iterator; | |||
| /** | |||
| * The constant pool of a Java class. The constant pool is a collection of | |||
| * constants used in a Java class file. It stores strings, constant values, | |||
| * class names, method names, field names etc. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @see <a href="http://java.sun.com/docs/books/vmspec/">The Java Virtual | |||
| * Machine Specification</a> | |||
| */ | |||
| public class ConstantPool | |||
| { | |||
| /** | |||
| * The entries in the constant pool. | |||
| */ | |||
| private ArrayList entries; | |||
| /** | |||
| * A Hashtable of UTF8 entries - used to get constant pool indexes of the | |||
| * UTF8 values quickly | |||
| */ | |||
| private Hashtable utf8Indexes; | |||
| /** | |||
| * Initialise the constant pool. | |||
| */ | |||
| public ConstantPool() | |||
| { | |||
| entries = new ArrayList(); | |||
| // The zero index is never present in the constant pool itself so | |||
| // we add a null entry for it | |||
| entries.add( null ); | |||
| utf8Indexes = new Hashtable(); | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_Class entry in the constant pool. | |||
| * | |||
| * @param className the name of the class for which the class entry index is | |||
| * required. | |||
| * @return the index at which the given class entry occurs in the constant | |||
| * pool or -1 if the value does not occur. | |||
| */ | |||
| public int getClassEntry( String className ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof ClassCPInfo ) | |||
| { | |||
| ClassCPInfo classinfo = (ClassCPInfo)element; | |||
| if( classinfo.getClassName().equals( className ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given constant value entry in the constant pool. | |||
| * | |||
| * @param constantValue the constant value for which the index is required. | |||
| * @return the index at which the given value entry occurs in the constant | |||
| * pool or -1 if the value does not occur. | |||
| */ | |||
| public int getConstantEntry( Object constantValue ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof ConstantCPInfo ) | |||
| { | |||
| ConstantCPInfo constantEntry = (ConstantCPInfo)element; | |||
| if( constantEntry.getValue().equals( constantValue ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get an constant pool entry at a particular index. | |||
| * | |||
| * @param index the index into the constant pool. | |||
| * @return the constant pool entry at that index. | |||
| */ | |||
| public ConstantPoolEntry getEntry( int index ) | |||
| { | |||
| return (ConstantPoolEntry)entries.get( index ); | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_FieldRef entry in the constant pool. | |||
| * | |||
| * @param fieldClassName the name of the class which contains the field | |||
| * being referenced. | |||
| * @param fieldName the name of the field being referenced. | |||
| * @param fieldType the type descriptor of the field being referenced. | |||
| * @return the index at which the given field ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getFieldRefEntry( String fieldClassName, String fieldName, String fieldType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof FieldRefCPInfo ) | |||
| { | |||
| FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo)element; | |||
| if( fieldRefEntry.getFieldClassName().equals( fieldClassName ) && fieldRefEntry.getFieldName().equals( fieldName ) | |||
| && fieldRefEntry.getFieldType().equals( fieldType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_InterfaceMethodRef entry in the | |||
| * constant pool. | |||
| * | |||
| * @param interfaceMethodClassName the name of the interface which contains | |||
| * the method being referenced. | |||
| * @param interfaceMethodName the name of the method being referenced. | |||
| * @param interfaceMethodType the type descriptor of the metho dbeing | |||
| * referenced. | |||
| * @return the index at which the given method ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getInterfaceMethodRefEntry( String interfaceMethodClassName, String interfaceMethodName, String interfaceMethodType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof InterfaceMethodRefCPInfo ) | |||
| { | |||
| InterfaceMethodRefCPInfo interfaceMethodRefEntry = (InterfaceMethodRefCPInfo)element; | |||
| if( interfaceMethodRefEntry.getInterfaceMethodClassName().equals( interfaceMethodClassName ) | |||
| && interfaceMethodRefEntry.getInterfaceMethodName().equals( interfaceMethodName ) | |||
| && interfaceMethodRefEntry.getInterfaceMethodType().equals( interfaceMethodType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_MethodRef entry in the constant pool. | |||
| * | |||
| * @param methodClassName the name of the class which contains the method | |||
| * being referenced. | |||
| * @param methodName the name of the method being referenced. | |||
| * @param methodType the type descriptor of the metho dbeing referenced. | |||
| * @return the index at which the given method ref entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getMethodRefEntry( String methodClassName, String methodName, String methodType ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof MethodRefCPInfo ) | |||
| { | |||
| MethodRefCPInfo methodRefEntry = (MethodRefCPInfo)element; | |||
| if( methodRefEntry.getMethodClassName().equals( methodClassName ) | |||
| && methodRefEntry.getMethodName().equals( methodName ) && methodRefEntry.getMethodType().equals( methodType ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given CONSTANT_NameAndType entry in the constant pool. | |||
| * | |||
| * @param name the name | |||
| * @param type the type | |||
| * @return the index at which the given NameAndType entry occurs in the | |||
| * constant pool or -1 if the value does not occur. | |||
| */ | |||
| public int getNameAndTypeEntry( String name, String type ) | |||
| { | |||
| int index = -1; | |||
| for( int i = 0; i < entries.size() && index == -1; ++i ) | |||
| { | |||
| Object element = entries.get( i ); | |||
| if( element instanceof NameAndTypeCPInfo ) | |||
| { | |||
| NameAndTypeCPInfo nameAndTypeEntry = (NameAndTypeCPInfo)element; | |||
| if( nameAndTypeEntry.getName().equals( name ) && nameAndTypeEntry.getType().equals( type ) ) | |||
| { | |||
| index = i; | |||
| } | |||
| } | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Get the index of a given UTF8 constant pool entry. | |||
| * | |||
| * @param value the string value of the UTF8 entry. | |||
| * @return the index at which the given string occurs in the constant pool | |||
| * or -1 if the value does not occur. | |||
| */ | |||
| public int getUTF8Entry( String value ) | |||
| { | |||
| int index = -1; | |||
| Integer indexInteger = (Integer)utf8Indexes.get( value ); | |||
| if( indexInteger != null ) | |||
| { | |||
| index = indexInteger.intValue(); | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Add an entry to the constant pool. | |||
| * | |||
| * @param entry the new entry to be added to the constant pool. | |||
| * @return the index into the constant pool at which the entry is stored. | |||
| */ | |||
| public int addEntry( ConstantPoolEntry entry ) | |||
| { | |||
| int index = entries.size(); | |||
| entries.add( entry ); | |||
| int numSlots = entry.getNumEntries(); | |||
| // add null entries for any additional slots required. | |||
| for( int j = 0; j < numSlots - 1; ++j ) | |||
| { | |||
| entries.add( null ); | |||
| } | |||
| if( entry instanceof Utf8CPInfo ) | |||
| { | |||
| Utf8CPInfo utf8Info = (Utf8CPInfo)entry; | |||
| utf8Indexes.put( utf8Info.getValue(), new Integer( index ) ); | |||
| } | |||
| return index; | |||
| } | |||
| /** | |||
| * Read the constant pool from a class input stream. | |||
| * | |||
| * @param classStream the DataInputStream of a class file. | |||
| * @throws IOException if there is a problem reading the constant pool from | |||
| * the stream | |||
| */ | |||
| public void read( DataInputStream classStream ) | |||
| throws IOException | |||
| { | |||
| int numEntries = classStream.readUnsignedShort(); | |||
| for( int i = 1; i < numEntries; ) | |||
| { | |||
| ConstantPoolEntry nextEntry = ConstantPoolEntry.readEntry( classStream ); | |||
| i += nextEntry.getNumEntries(); | |||
| addEntry( nextEntry ); | |||
| } | |||
| } | |||
| /** | |||
| * Resolve the entries in the constant pool. Resolution of the constant pool | |||
| * involves transforming indexes to other constant pool entries into the | |||
| * actual data for that entry. | |||
| */ | |||
| public void resolve() | |||
| { | |||
| for( Iterator i = entries.iterator(); i.hasNext(); ) | |||
| { | |||
| ConstantPoolEntry poolInfo = (ConstantPoolEntry)i.next(); | |||
| if( poolInfo != null && !poolInfo.isResolved() ) | |||
| { | |||
| poolInfo.resolve( this ); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Get the size of the constant pool. | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public int size() | |||
| { | |||
| return entries.size(); | |||
| } | |||
| /** | |||
| * Dump the constant pool to a string. | |||
| * | |||
| * @return the constant pool entries as strings | |||
| */ | |||
| public String toString() | |||
| { | |||
| StringBuffer sb = new StringBuffer( "\n" ); | |||
| int size = entries.size(); | |||
| for( int i = 0; i < size; ++i ) | |||
| { | |||
| sb.append( "[" + i + "] = " + getEntry( i ) + "\n" ); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| } | |||
| @@ -1,243 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * An entry in the constant pool. This class contains a represenation of the | |||
| * constant pool entries. It is an abstract base class for all the different | |||
| * forms of constant pool entry. | |||
| * | |||
| * @author Conor MacNeill | |||
| * @see ConstantPool | |||
| */ | |||
| public abstract class ConstantPoolEntry | |||
| { | |||
| /** | |||
| * Tag value for UTF8 entries. | |||
| */ | |||
| public final static int CONSTANT_Utf8 = 1; | |||
| /** | |||
| * Tag value for Integer entries. | |||
| */ | |||
| public final static int CONSTANT_Integer = 3; | |||
| /** | |||
| * Tag value for Float entries. | |||
| */ | |||
| public final static int CONSTANT_Float = 4; | |||
| /** | |||
| * Tag value for Long entries. | |||
| */ | |||
| public final static int CONSTANT_Long = 5; | |||
| /** | |||
| * Tag value for Double entries. | |||
| */ | |||
| public final static int CONSTANT_Double = 6; | |||
| /** | |||
| * Tag value for Class entries. | |||
| */ | |||
| public final static int CONSTANT_Class = 7; | |||
| /** | |||
| * Tag value for String entries. | |||
| */ | |||
| public final static int CONSTANT_String = 8; | |||
| /** | |||
| * Tag value for Field Reference entries. | |||
| */ | |||
| public final static int CONSTANT_FieldRef = 9; | |||
| /** | |||
| * Tag value for Method Reference entries. | |||
| */ | |||
| public final static int CONSTANT_MethodRef = 10; | |||
| /** | |||
| * Tag value for Interface Method Reference entries. | |||
| */ | |||
| public final static int CONSTANT_InterfaceMethodRef = 11; | |||
| /** | |||
| * Tag value for Name and Type entries. | |||
| */ | |||
| public final static int CONSTANT_NameAndType = 12; | |||
| /** | |||
| * The number of slots in the constant pool, occupied by this entry. | |||
| */ | |||
| private int numEntries; | |||
| /** | |||
| * A flag which indiciates if this entry has been resolved or not. | |||
| */ | |||
| private boolean resolved; | |||
| /** | |||
| * This entry's tag which identifies the type of this constant pool entry. | |||
| */ | |||
| private int tag; | |||
| /** | |||
| * Initialse the constant pool entry. | |||
| * | |||
| * @param tagValue the tag value which identifies which type of constant | |||
| * pool entry this is. | |||
| * @param entries the number of constant pool entry slots this entry | |||
| * occupies. | |||
| */ | |||
| public ConstantPoolEntry( int tagValue, int entries ) | |||
| { | |||
| tag = tagValue; | |||
| numEntries = entries; | |||
| resolved = false; | |||
| } | |||
| /** | |||
| * Read a constant pool entry from a stream. This is a factory method which | |||
| * reads a constant pool entry form a stream and returns the appropriate | |||
| * subclass for the entry. | |||
| * | |||
| * @param cpStream the stream from which the constant pool entry is to be | |||
| * read. | |||
| * @return Description of the Returned Value | |||
| * @exception IOException Description of Exception | |||
| * @returns the appropriate ConstantPoolEntry subclass representing the | |||
| * constant pool entry from the stream. | |||
| * @throws IOExcception if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public static ConstantPoolEntry readEntry( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| ConstantPoolEntry cpInfo = null; | |||
| int cpTag = cpStream.readUnsignedByte(); | |||
| switch( cpTag ) | |||
| { | |||
| case CONSTANT_Utf8: | |||
| cpInfo = new Utf8CPInfo(); | |||
| break; | |||
| case CONSTANT_Integer: | |||
| cpInfo = new IntegerCPInfo(); | |||
| break; | |||
| case CONSTANT_Float: | |||
| cpInfo = new FloatCPInfo(); | |||
| break; | |||
| case CONSTANT_Long: | |||
| cpInfo = new LongCPInfo(); | |||
| break; | |||
| case CONSTANT_Double: | |||
| cpInfo = new DoubleCPInfo(); | |||
| break; | |||
| case CONSTANT_Class: | |||
| cpInfo = new ClassCPInfo(); | |||
| break; | |||
| case CONSTANT_String: | |||
| cpInfo = new StringCPInfo(); | |||
| break; | |||
| case CONSTANT_FieldRef: | |||
| cpInfo = new FieldRefCPInfo(); | |||
| break; | |||
| case CONSTANT_MethodRef: | |||
| cpInfo = new MethodRefCPInfo(); | |||
| break; | |||
| case CONSTANT_InterfaceMethodRef: | |||
| cpInfo = new InterfaceMethodRefCPInfo(); | |||
| break; | |||
| case CONSTANT_NameAndType: | |||
| cpInfo = new NameAndTypeCPInfo(); | |||
| break; | |||
| default: | |||
| throw new ClassFormatError( "Invalid Constant Pool entry Type " + cpTag ); | |||
| } | |||
| cpInfo.read( cpStream ); | |||
| return cpInfo; | |||
| } | |||
| /** | |||
| * Get the number of Constant Pool Entry slots within the constant pool | |||
| * occupied by this entry. | |||
| * | |||
| * @return the number of slots used. | |||
| */ | |||
| public final int getNumEntries() | |||
| { | |||
| return numEntries; | |||
| } | |||
| /** | |||
| * Get the Entry's type tag. | |||
| * | |||
| * @return The Tag value of this entry | |||
| */ | |||
| public int getTag() | |||
| { | |||
| return tag; | |||
| } | |||
| /** | |||
| * Indicates whether this entry has been resolved. In general a constant | |||
| * pool entry can reference another constant pool entry by its index value. | |||
| * Resolution involves replacing this index value with the constant pool | |||
| * entry at that index. | |||
| * | |||
| * @return true if this entry has been resolved. | |||
| */ | |||
| public boolean isResolved() | |||
| { | |||
| return resolved; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public abstract void read( DataInputStream cpStream ) | |||
| throws IOException; | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| resolved = true; | |||
| } | |||
| } | |||
| @@ -1,50 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * The constant pool entry subclass used to represent double constant values. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class DoubleCPInfo extends ConstantCPInfo | |||
| { | |||
| public DoubleCPInfo() | |||
| { | |||
| super( CONSTANT_Double, 2 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Double( cpStream.readDouble() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Double Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,111 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A FieldRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class FieldRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String fieldClassName; | |||
| private String fieldName; | |||
| private String fieldType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public FieldRefCPInfo() | |||
| { | |||
| super( CONSTANT_FieldRef, 1 ); | |||
| } | |||
| public String getFieldClassName() | |||
| { | |||
| return fieldClassName; | |||
| } | |||
| public String getFieldName() | |||
| { | |||
| return fieldName; | |||
| } | |||
| public String getFieldType() | |||
| { | |||
| return fieldType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo fieldClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| fieldClass.resolve( constantPool ); | |||
| fieldClassName = fieldClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| fieldName = nt.getName(); | |||
| fieldType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Field : Class = " + fieldClassName + ", name = " + fieldName + ", type = " + fieldType; | |||
| } | |||
| else | |||
| { | |||
| value = "Field : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A Float CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class FloatCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public FloatCPInfo() | |||
| { | |||
| super( CONSTANT_Float, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Float( cpStream.readFloat() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Float Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * An Integer CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class IntegerCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public IntegerCPInfo() | |||
| { | |||
| super( CONSTANT_Integer, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Integer( cpStream.readInt() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Integer Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,112 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A InterfaceMethodRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class InterfaceMethodRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String interfaceMethodClassName; | |||
| private String interfaceMethodName; | |||
| private String interfaceMethodType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public InterfaceMethodRefCPInfo() | |||
| { | |||
| super( CONSTANT_InterfaceMethodRef, 1 ); | |||
| } | |||
| public String getInterfaceMethodClassName() | |||
| { | |||
| return interfaceMethodClassName; | |||
| } | |||
| public String getInterfaceMethodName() | |||
| { | |||
| return interfaceMethodName; | |||
| } | |||
| public String getInterfaceMethodType() | |||
| { | |||
| return interfaceMethodType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo interfaceMethodClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| interfaceMethodClass.resolve( constantPool ); | |||
| interfaceMethodClassName = interfaceMethodClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| interfaceMethodName = nt.getName(); | |||
| interfaceMethodType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "InterfaceMethod : Class = " + interfaceMethodClassName + ", name = " + interfaceMethodName + ", type = " | |||
| + interfaceMethodType; | |||
| } | |||
| else | |||
| { | |||
| value = "InterfaceMethod : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A Long CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class LongCPInfo extends ConstantCPInfo | |||
| { | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public LongCPInfo() | |||
| { | |||
| super( CONSTANT_Long, 2 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| setValue( new Long( cpStream.readLong() ) ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "Long Constant Pool Entry: " + getValue(); | |||
| } | |||
| } | |||
| @@ -1,111 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A MethodRef CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class MethodRefCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int classIndex; | |||
| private String methodClassName; | |||
| private String methodName; | |||
| private String methodType; | |||
| private int nameAndTypeIndex; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public MethodRefCPInfo() | |||
| { | |||
| super( CONSTANT_MethodRef, 1 ); | |||
| } | |||
| public String getMethodClassName() | |||
| { | |||
| return methodClassName; | |||
| } | |||
| public String getMethodName() | |||
| { | |||
| return methodName; | |||
| } | |||
| public String getMethodType() | |||
| { | |||
| return methodType; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| classIndex = cpStream.readUnsignedShort(); | |||
| nameAndTypeIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| ClassCPInfo methodClass = (ClassCPInfo)constantPool.getEntry( classIndex ); | |||
| methodClass.resolve( constantPool ); | |||
| methodClassName = methodClass.getClassName(); | |||
| NameAndTypeCPInfo nt = (NameAndTypeCPInfo)constantPool.getEntry( nameAndTypeIndex ); | |||
| nt.resolve( constantPool ); | |||
| methodName = nt.getName(); | |||
| methodType = nt.getType(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Method : Class = " + methodClassName + ", name = " + methodName + ", type = " + methodType; | |||
| } | |||
| else | |||
| { | |||
| value = "Method : Class index = " + classIndex + ", name and type index = " + nameAndTypeIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,95 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A NameAndType CP Info | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class NameAndTypeCPInfo extends ConstantPoolEntry | |||
| { | |||
| private int descriptorIndex; | |||
| private String name; | |||
| private int nameIndex; | |||
| private String type; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public NameAndTypeCPInfo() | |||
| { | |||
| super( CONSTANT_NameAndType, 1 ); | |||
| } | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public String getType() | |||
| { | |||
| return type; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| nameIndex = cpStream.readUnsignedShort(); | |||
| descriptorIndex = cpStream.readUnsignedShort(); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| name = ( (Utf8CPInfo)constantPool.getEntry( nameIndex ) ).getValue(); | |||
| type = ( (Utf8CPInfo)constantPool.getEntry( descriptorIndex ) ).getValue(); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| String value; | |||
| if( isResolved() ) | |||
| { | |||
| value = "Name = " + name + ", type = " + type; | |||
| } | |||
| else | |||
| { | |||
| value = "Name index = " + nameIndex + ", descriptor index = " + descriptorIndex; | |||
| } | |||
| return value; | |||
| } | |||
| } | |||
| @@ -1,71 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A String Constant Pool Entry. The String info contains an index into the | |||
| * constant pool where a UTF8 string is stored. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class StringCPInfo extends ConstantCPInfo | |||
| { | |||
| private int index; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public StringCPInfo() | |||
| { | |||
| super( CONSTANT_String, 1 ); | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| index = cpStream.readUnsignedShort(); | |||
| setValue( "unresolved" ); | |||
| } | |||
| /** | |||
| * Resolve this constant pool entry with respect to its dependents in the | |||
| * constant pool. | |||
| * | |||
| * @param constantPool the constant pool of which this entry is a member and | |||
| * against which this entry is to be resolved. | |||
| */ | |||
| public void resolve( ConstantPool constantPool ) | |||
| { | |||
| setValue( ( (Utf8CPInfo)constantPool.getEntry( index ) ).getValue() ); | |||
| super.resolve( constantPool ); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "String Constant Pool Entry for " + getValue() + "[" + index + "]"; | |||
| } | |||
| } | |||
| @@ -1,60 +0,0 @@ | |||
| /* | |||
| * Copyright (C) The Apache Software Foundation. All rights reserved. | |||
| * | |||
| * This software is published under the terms of the Apache Software License | |||
| * version 1.1, a copy of which has been included with this distribution in | |||
| * the LICENSE.txt file. | |||
| */ | |||
| package org.apache.tools.ant.taskdefs.optional.depend.constantpool; | |||
| import java.io.DataInputStream; | |||
| import java.io.IOException; | |||
| /** | |||
| * A UTF8 Constant Pool Entry. | |||
| * | |||
| * @author Conor MacNeill | |||
| */ | |||
| public class Utf8CPInfo extends ConstantPoolEntry | |||
| { | |||
| private String value; | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| public Utf8CPInfo() | |||
| { | |||
| super( CONSTANT_Utf8, 1 ); | |||
| } | |||
| public String getValue() | |||
| { | |||
| return value; | |||
| } | |||
| /** | |||
| * read a constant pool entry from a class stream. | |||
| * | |||
| * @param cpStream the DataInputStream which contains the constant pool | |||
| * entry to be read. | |||
| * @throws IOException if there is a problem reading the entry from the | |||
| * stream. | |||
| */ | |||
| public void read( DataInputStream cpStream ) | |||
| throws IOException | |||
| { | |||
| value = cpStream.readUTF(); | |||
| } | |||
| /** | |||
| * Print a readable version of the constant pool entry. | |||
| * | |||
| * @return the string representation of this constant pool entry. | |||
| */ | |||
| public String toString() | |||
| { | |||
| return "UTF8 Value = " + value; | |||
| } | |||
| } | |||