diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java deleted file mode 100644 index 777f617bf..000000000 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java +++ /dev/null @@ -1,116 +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.jlink; - -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Provides a quick and dirty way to determine the true name of a class given - * just an InputStream. Reads in just enough to perform this minimal task only. - * - * @author RT - */ -public class ClassNameReader extends Object -{ - - public static String getClassName( InputStream input ) - throws IOException - { - DataInputStream data = new DataInputStream( input ); - // verify this is a valid class file. - int cookie = data.readInt(); - if( cookie != 0xCAFEBABE ) - { - return null; - } - int version = data.readInt(); - // read the constant pool. - ConstantPool constants = new ConstantPool( data ); - Object[] values = constants.values; - // read access flags and class index. - int accessFlags = data.readUnsignedShort(); - int classIndex = data.readUnsignedShort(); - Integer stringIndex = (Integer)values[ classIndex ]; - String className = (String)values[ stringIndex.intValue() ]; - return className; - } - -} - -/** - * Reads just enough of a class file to determine the class' full name.

- * - * Extremely minimal constant pool implementation, mainly to support extracting - * strings from a class file. - * - * @author Patrick C. Beard . - */ -class ConstantPool extends Object -{ - - final static byte UTF8 = 1, UNUSED = 2, INTEGER = 3, FLOAT = 4, LONG = 5, DOUBLE = 6, - CLASS = 7, STRING = 8, FIELDREF = 9, METHODREF = 10, - INTERFACEMETHODREF = 11, NAMEANDTYPE = 12; - - byte[] types; - - Object[] values; - - ConstantPool( DataInput data ) - throws IOException - { - super(); - - int count = data.readUnsignedShort(); - types = new byte[ count ]; - values = new Object[ count ]; - // read in all constant pool entries. - for( int i = 1; i < count; i++ ) - { - byte type = data.readByte(); - types[ i ] = type; - switch( type ) - { - case UTF8: - values[ i ] = data.readUTF(); - break; - case UNUSED: - break; - case INTEGER: - values[ i ] = new Integer( data.readInt() ); - break; - case FLOAT: - values[ i ] = new Float( data.readFloat() ); - break; - case LONG: - values[ i ] = new Long( data.readLong() ); - ++i; - break; - case DOUBLE: - values[ i ] = new Double( data.readDouble() ); - ++i; - break; - case CLASS: - case STRING: - values[ i ] = new Integer( data.readUnsignedShort() ); - break; - case FIELDREF: - case METHODREF: - case INTERFACEMETHODREF: - case NAMEANDTYPE: - values[ i ] = new Integer( data.readInt() ); - break; - } - } - } - -} - diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java deleted file mode 100644 index 58b57984a..000000000 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java +++ /dev/null @@ -1,210 +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.jlink; - -import java.io.File; -import org.apache.myrmidon.api.TaskException; -import org.apache.tools.ant.taskdefs.MatchingTask; -import org.apache.tools.ant.types.Path; - -/** - * This class defines objects that can link together various jar and zip files. - *

- * - * It is basically a wrapper for the jlink code written originally by Patrick Beard . The classes - * org.apache.tools.ant.taskdefs.optional.jlink.Jlink and - * org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader support this - * class.

- * - * For example: - *

- * <jlink compress="false" outfile="out.jar"/>
- *   <mergefiles>
- *     <pathelement path="${build.dir}/mergefoo.jar"/>
- *     <pathelement path="${build.dir}/mergebar.jar"/>
- *   </mergefiles>
- *   <addfiles>
- *     <pathelement path="${build.dir}/mac.jar"/>
- *     <pathelement path="${build.dir}/pc.zip"/>
- *   </addfiles>
- * </jlink>
- * 
- * - * @author Matthew Kuperus Heun - * - */ -public class JlinkTask extends MatchingTask -{ - - private File outfile = null; - - private Path mergefiles = null; - - private Path addfiles = null; - - private boolean compress = false; - - private String ps = System.getProperty( "path.separator" ); - - /** - * Sets the files to be added into the output. - * - * @param addfiles The new Addfiles value - */ - public void setAddfiles( Path addfiles ) - throws TaskException - { - if( this.addfiles == null ) - { - this.addfiles = addfiles; - } - else - { - this.addfiles.append( addfiles ); - } - } - - /** - * Defines whether or not the output should be compacted. - * - * @param compress The new Compress value - */ - public void setCompress( boolean compress ) - { - this.compress = compress; - } - - /** - * Sets the files to be merged into the output. - * - * @param mergefiles The new Mergefiles value - */ - public void setMergefiles( Path mergefiles ) - throws TaskException - { - if( this.mergefiles == null ) - { - this.mergefiles = mergefiles; - } - else - { - this.mergefiles.append( mergefiles ); - } - } - - /** - * The output file for this run of jlink. Usually a jar or zip file. - * - * @param outfile The new Outfile value - */ - public void setOutfile( File outfile ) - { - this.outfile = outfile; - } - - /** - * Establishes the object that contains the files to be added to the output. - * - * @return Description of the Returned Value - */ - public Path createAddfiles() - throws TaskException - { - if( this.addfiles == null ) - { - this.addfiles = new Path(); - } - return this.addfiles.createPath(); - } - - /** - * Establishes the object that contains the files to be merged into the - * output. - * - * @return Description of the Returned Value - */ - public Path createMergefiles() - throws TaskException - { - if( this.mergefiles == null ) - { - this.mergefiles = new Path(); - } - return this.mergefiles.createPath(); - } - - /** - * Does the adding and merging. - * - * @exception TaskException Description of Exception - */ - public void execute() - throws TaskException - { - //Be sure everything has been set. - if( outfile == null ) - { - throw new TaskException( "outfile attribute is required! Please set." ); - } - if( !haveAddFiles() && !haveMergeFiles() ) - { - throw new TaskException( "addfiles or mergefiles required! Please set." ); - } - getLogger().info( "linking: " + outfile.getPath() ); - getLogger().debug( "compression: " + compress ); - jlink linker = new jlink(); - linker.setOutfile( outfile.getPath() ); - linker.setCompression( compress ); - if( haveMergeFiles() ) - { - getLogger().debug( "merge files: " + mergefiles.toString() ); - linker.addMergeFiles( mergefiles.list() ); - } - if( haveAddFiles() ) - { - getLogger().debug( "add files: " + addfiles.toString() ); - linker.addAddFiles( addfiles.list() ); - } - try - { - linker.link(); - } - catch( Exception ex ) - { - throw new TaskException( "Error", ex ); - } - } - - private boolean haveAddFiles() - throws TaskException - { - return haveEntries( addfiles ); - } - - private boolean haveEntries( Path p ) - throws TaskException - { - if( p == null ) - { - return false; - } - if( p.size() > 0 ) - { - return true; - } - return false; - } - - private boolean haveMergeFiles() - throws TaskException - { - return haveEntries( mergefiles ); - } -} - diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java deleted file mode 100644 index c1b33c9bb..000000000 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java +++ /dev/null @@ -1,469 +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.jlink; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.zip.CRC32; -import java.util.zip.Deflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -public class jlink extends Object -{ - - private String outfile = null; - - private ArrayList mergefiles = new ArrayList( 10 ); - - private ArrayList addfiles = new ArrayList( 10 ); - - private boolean compression = false; - - byte[] buffer = new byte[ 8192 ]; - - public static void main( String[] args ) - { - // jlink output input1 ... inputN - if( args.length < 2 ) - { - System.out.println( "usage: jlink output input1 ... inputN" ); - System.exit( 1 ); - } - jlink linker = new jlink(); - linker.setOutfile( args[ 0 ] ); - //To maintain compatibility with the command-line version, we will only add files to be merged. - for( int i = 1; i < args.length; i++ ) - { - linker.addMergeFile( args[ i ] ); - } - try - { - linker.link(); - } - catch( Exception ex ) - { - System.err.print( ex.getMessage() ); - } - } - - /** - * Determines whether output will be compressed. - * - * @param compress The new Compression value - */ - public void setCompression( boolean compress ) - { - this.compression = compress; - } - - /** - * The file that will be created by this instance of jlink. - * - * @param outfile The new Outfile value - */ - public void setOutfile( String outfile ) - { - if( outfile == null ) - { - return; - } - this.outfile = outfile; - } - - /** - * Adds a file to be added into the output. - * - * @param addfile The feature to be added to the AddFile attribute - */ - public void addAddFile( String addfile ) - { - if( addfile == null ) - { - return; - } - addfiles.add( addfile ); - } - - /** - * Adds several file to be added into the output. - * - * @param addfiles The feature to be added to the AddFiles attribute - */ - public void addAddFiles( String[] addfiles ) - { - if( addfiles == null ) - { - return; - } - for( int i = 0; i < addfiles.length; i++ ) - { - addAddFile( addfiles[ i ] ); - } - } - - /** - * Adds a file to be merged into the output. - * - * @param mergefile The feature to be added to the MergeFile attribute - */ - public void addMergeFile( String mergefile ) - { - if( mergefile == null ) - { - return; - } - mergefiles.add( mergefile ); - } - - /** - * Adds several files to be merged into the output. - * - * @param mergefiles The feature to be added to the MergeFiles attribute - */ - public void addMergeFiles( String[] mergefiles ) - { - if( mergefiles == null ) - { - return; - } - for( int i = 0; i < mergefiles.length; i++ ) - { - addMergeFile( mergefiles[ i ] ); - } - } - - /** - * Performs the linking of files. Addfiles are added to the output as-is. - * For example, a jar file is added to the output as a jar file. However, - * mergefiles are first examined for their type. If it is a jar or zip file, - * the contents will be extracted from the mergefile and entered into the - * output. If a zip or jar file is encountered in a subdirectory it will be - * added, not merged. If a directory is encountered, it becomes the root - * entry of all the files below it. Thus, you can provide multiple, disjoint - * directories, as addfiles: they will all be added in a rational manner to - * outfile. - * - * @exception Exception Description of Exception - */ - public void link() - throws Exception - { - ZipOutputStream output = new ZipOutputStream( new FileOutputStream( outfile ) ); - if( compression ) - { - output.setMethod( ZipOutputStream.DEFLATED ); - output.setLevel( Deflater.DEFAULT_COMPRESSION ); - } - else - { - output.setMethod( ZipOutputStream.STORED ); - } - Iterator merges = mergefiles.iterator(); - while( merges.hasNext() ) - { - String path = (String)merges.next(); - File f = new File( path ); - if( f.getName().endsWith( ".jar" ) || f.getName().endsWith( ".zip" ) ) - { - //Do the merge - mergeZipJarContents( output, f ); - } - else - { - //Add this file to the addfiles ArrayList and add it - //later at the top level of the output file. - addAddFile( path ); - } - } - Iterator adds = addfiles.iterator(); - while( adds.hasNext() ) - { - String name = (String)adds.next(); - File f = new File( name ); - if( f.isDirectory() ) - { - //System.out.println("in jlink: adding directory contents of " + f.getPath()); - addDirContents( output, f, f.getName() + '/', compression ); - } - else - { - addFile( output, f, "", compression ); - } - } - if( output != null ) - { - try - { - output.close(); - } - catch( IOException ioe ) - { - } - } - } - - /* - * Gets the name of an entry in the file. This is the real name - * which for a class is the name of the package with the class - * name appended. - */ - private String getEntryName( File file, String prefix ) - { - String name = file.getName(); - if( !name.endsWith( ".class" ) ) - { - // see if the file is in fact a .class file, and determine its actual name. - try - { - InputStream input = new FileInputStream( file ); - String className = ClassNameReader.getClassName( input ); - input.close(); - if( className != null ) - { - return className.replace( '.', '/' ) + ".class"; - } - } - catch( IOException ioe ) - { - } - } - System.out.println( "From " + file.getPath() + " and prefix " + prefix + ", creating entry " + prefix + name ); - return ( prefix + name ); - } - - /* - * Adds contents of a directory to the output. - */ - private void addDirContents( ZipOutputStream output, File dir, String prefix, boolean compress ) - throws IOException - { - String[] contents = dir.list(); - for( int i = 0; i < contents.length; ++i ) - { - String name = contents[ i ]; - File file = new File( dir, name ); - if( file.isDirectory() ) - { - addDirContents( output, file, prefix + name + '/', compress ); - } - else - { - addFile( output, file, prefix, compress ); - } - } - } - - /* - * Adds a file to the output stream. - */ - private void addFile( ZipOutputStream output, File file, String prefix, boolean compress ) - throws IOException - { - //Make sure file exists - long checksum = 0; - if( !file.exists() ) - { - return; - } - ZipEntry entry = new ZipEntry( getEntryName( file, prefix ) ); - entry.setTime( file.lastModified() ); - entry.setSize( file.length() ); - if( !compress ) - { - entry.setCrc( calcChecksum( file ) ); - } - FileInputStream input = new FileInputStream( file ); - addToOutputStream( output, input, entry ); - } - - /* - * A convenience method that several other methods might call. - */ - private void addToOutputStream( ZipOutputStream output, InputStream input, ZipEntry ze ) - throws IOException - { - try - { - output.putNextEntry( ze ); - } - catch( ZipException zipEx ) - { - //This entry already exists. So, go with the first one. - input.close(); - return; - } - int numBytes = -1; - while( ( numBytes = input.read( buffer ) ) > 0 ) - { - output.write( buffer, 0, numBytes ); - } - output.closeEntry(); - input.close(); - } - - /* - * Necessary in the case where you add a entry that - * is not compressed. - */ - private long calcChecksum( File f ) - throws IOException - { - BufferedInputStream in = new BufferedInputStream( new FileInputStream( f ) ); - return calcChecksum( in, f.length() ); - } - - /* - * Necessary in the case where you add a entry that - * is not compressed. - */ - private long calcChecksum( InputStream in, long size ) - throws IOException - { - CRC32 crc = new CRC32(); - int len = buffer.length; - int count = -1; - int haveRead = 0; - while( ( count = in.read( buffer, 0, len ) ) > 0 ) - { - haveRead += count; - crc.update( buffer, 0, count ); - } - in.close(); - return crc.getValue(); - } - - /* - * Actually performs the merging of f into the output. - * f should be a zip or jar file. - */ - private void mergeZipJarContents( ZipOutputStream output, File f ) - throws IOException - { - //Check to see that the file with name "name" exists. - if( !f.exists() ) - { - return; - } - ZipFile zipf = new ZipFile( f ); - Enumeration entries = zipf.entries(); - while( entries.hasMoreElements() ) - { - ZipEntry inputEntry = (ZipEntry)entries.nextElement(); - //Ignore manifest entries. They're bound to cause conflicts between - //files that are being merged. User should supply their own - //manifest file when doing the merge. - String inputEntryName = inputEntry.getName(); - int index = inputEntryName.indexOf( "META-INF" ); - if( index < 0 ) - { - //META-INF not found in the name of the entry. Go ahead and process it. - try - { - output.putNextEntry( processEntry( zipf, inputEntry ) ); - } - catch( ZipException ex ) - { - //If we get here, it could be because we are trying to put a - //directory entry that already exists. - //For example, we're trying to write "com", but a previous - //entry from another mergefile was called "com". - //In that case, just ignore the error and go on to the - //next entry. - String mess = ex.getMessage(); - if( mess.indexOf( "duplicate" ) >= 0 ) - { - //It was the duplicate entry. - continue; - } - else - { - //I hate to admit it, but we don't know what happened here. Throw the Exception. - throw ex; - } - } - InputStream in = zipf.getInputStream( inputEntry ); - int len = buffer.length; - int count = -1; - while( ( count = in.read( buffer, 0, len ) ) > 0 ) - { - output.write( buffer, 0, count ); - } - in.close(); - output.closeEntry(); - } - } - zipf.close(); - } - - /* - * A method that does the work on a given entry in a mergefile. - * The big deal is to set the right parameters in the ZipEntry - * on the output stream. - */ - private ZipEntry processEntry( ZipFile zip, ZipEntry inputEntry ) - throws IOException - { - /* - * First, some notes. - * On MRJ 2.2.2, getting the size, compressed size, and CRC32 from the - * ZipInputStream does not work for compressed (deflated) files. Those calls return -1. - * For uncompressed (stored) files, those calls do work. - * However, using ZipFile.getEntries() works for both compressed and - * uncompressed files. - * Now, from some simple testing I did, it seems that the value of CRC-32 is - * independent of the compression setting. So, it should be easy to pass this - * information on to the output entry. - */ - String name = inputEntry.getName(); - if( !( inputEntry.isDirectory() || name.endsWith( ".class" ) ) ) - { - try - { - InputStream input = zip.getInputStream( zip.getEntry( name ) ); - String className = ClassNameReader.getClassName( input ); - input.close(); - if( className != null ) - { - name = className.replace( '.', '/' ) + ".class"; - } - } - catch( IOException ioe ) - { - } - } - ZipEntry outputEntry = new ZipEntry( name ); - outputEntry.setTime( inputEntry.getTime() ); - outputEntry.setExtra( inputEntry.getExtra() ); - outputEntry.setComment( inputEntry.getComment() ); - outputEntry.setTime( inputEntry.getTime() ); - if( compression ) - { - outputEntry.setMethod( ZipEntry.DEFLATED ); - //Note, don't need to specify size or crc for compressed files. - } - else - { - outputEntry.setMethod( ZipEntry.STORED ); - outputEntry.setCrc( inputEntry.getCrc() ); - outputEntry.setSize( inputEntry.getSize() ); - } - return outputEntry; - } - -} - diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java deleted file mode 100644 index 777f617bf..000000000 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java +++ /dev/null @@ -1,116 +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.jlink; - -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Provides a quick and dirty way to determine the true name of a class given - * just an InputStream. Reads in just enough to perform this minimal task only. - * - * @author RT - */ -public class ClassNameReader extends Object -{ - - public static String getClassName( InputStream input ) - throws IOException - { - DataInputStream data = new DataInputStream( input ); - // verify this is a valid class file. - int cookie = data.readInt(); - if( cookie != 0xCAFEBABE ) - { - return null; - } - int version = data.readInt(); - // read the constant pool. - ConstantPool constants = new ConstantPool( data ); - Object[] values = constants.values; - // read access flags and class index. - int accessFlags = data.readUnsignedShort(); - int classIndex = data.readUnsignedShort(); - Integer stringIndex = (Integer)values[ classIndex ]; - String className = (String)values[ stringIndex.intValue() ]; - return className; - } - -} - -/** - * Reads just enough of a class file to determine the class' full name.

- * - * Extremely minimal constant pool implementation, mainly to support extracting - * strings from a class file. - * - * @author Patrick C. Beard . - */ -class ConstantPool extends Object -{ - - final static byte UTF8 = 1, UNUSED = 2, INTEGER = 3, FLOAT = 4, LONG = 5, DOUBLE = 6, - CLASS = 7, STRING = 8, FIELDREF = 9, METHODREF = 10, - INTERFACEMETHODREF = 11, NAMEANDTYPE = 12; - - byte[] types; - - Object[] values; - - ConstantPool( DataInput data ) - throws IOException - { - super(); - - int count = data.readUnsignedShort(); - types = new byte[ count ]; - values = new Object[ count ]; - // read in all constant pool entries. - for( int i = 1; i < count; i++ ) - { - byte type = data.readByte(); - types[ i ] = type; - switch( type ) - { - case UTF8: - values[ i ] = data.readUTF(); - break; - case UNUSED: - break; - case INTEGER: - values[ i ] = new Integer( data.readInt() ); - break; - case FLOAT: - values[ i ] = new Float( data.readFloat() ); - break; - case LONG: - values[ i ] = new Long( data.readLong() ); - ++i; - break; - case DOUBLE: - values[ i ] = new Double( data.readDouble() ); - ++i; - break; - case CLASS: - case STRING: - values[ i ] = new Integer( data.readUnsignedShort() ); - break; - case FIELDREF: - case METHODREF: - case INTERFACEMETHODREF: - case NAMEANDTYPE: - values[ i ] = new Integer( data.readInt() ); - break; - } - } - } - -} - diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java deleted file mode 100644 index 58b57984a..000000000 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java +++ /dev/null @@ -1,210 +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.jlink; - -import java.io.File; -import org.apache.myrmidon.api.TaskException; -import org.apache.tools.ant.taskdefs.MatchingTask; -import org.apache.tools.ant.types.Path; - -/** - * This class defines objects that can link together various jar and zip files. - *

- * - * It is basically a wrapper for the jlink code written originally by Patrick Beard . The classes - * org.apache.tools.ant.taskdefs.optional.jlink.Jlink and - * org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader support this - * class.

- * - * For example: - *

- * <jlink compress="false" outfile="out.jar"/>
- *   <mergefiles>
- *     <pathelement path="${build.dir}/mergefoo.jar"/>
- *     <pathelement path="${build.dir}/mergebar.jar"/>
- *   </mergefiles>
- *   <addfiles>
- *     <pathelement path="${build.dir}/mac.jar"/>
- *     <pathelement path="${build.dir}/pc.zip"/>
- *   </addfiles>
- * </jlink>
- * 
- * - * @author Matthew Kuperus Heun - * - */ -public class JlinkTask extends MatchingTask -{ - - private File outfile = null; - - private Path mergefiles = null; - - private Path addfiles = null; - - private boolean compress = false; - - private String ps = System.getProperty( "path.separator" ); - - /** - * Sets the files to be added into the output. - * - * @param addfiles The new Addfiles value - */ - public void setAddfiles( Path addfiles ) - throws TaskException - { - if( this.addfiles == null ) - { - this.addfiles = addfiles; - } - else - { - this.addfiles.append( addfiles ); - } - } - - /** - * Defines whether or not the output should be compacted. - * - * @param compress The new Compress value - */ - public void setCompress( boolean compress ) - { - this.compress = compress; - } - - /** - * Sets the files to be merged into the output. - * - * @param mergefiles The new Mergefiles value - */ - public void setMergefiles( Path mergefiles ) - throws TaskException - { - if( this.mergefiles == null ) - { - this.mergefiles = mergefiles; - } - else - { - this.mergefiles.append( mergefiles ); - } - } - - /** - * The output file for this run of jlink. Usually a jar or zip file. - * - * @param outfile The new Outfile value - */ - public void setOutfile( File outfile ) - { - this.outfile = outfile; - } - - /** - * Establishes the object that contains the files to be added to the output. - * - * @return Description of the Returned Value - */ - public Path createAddfiles() - throws TaskException - { - if( this.addfiles == null ) - { - this.addfiles = new Path(); - } - return this.addfiles.createPath(); - } - - /** - * Establishes the object that contains the files to be merged into the - * output. - * - * @return Description of the Returned Value - */ - public Path createMergefiles() - throws TaskException - { - if( this.mergefiles == null ) - { - this.mergefiles = new Path(); - } - return this.mergefiles.createPath(); - } - - /** - * Does the adding and merging. - * - * @exception TaskException Description of Exception - */ - public void execute() - throws TaskException - { - //Be sure everything has been set. - if( outfile == null ) - { - throw new TaskException( "outfile attribute is required! Please set." ); - } - if( !haveAddFiles() && !haveMergeFiles() ) - { - throw new TaskException( "addfiles or mergefiles required! Please set." ); - } - getLogger().info( "linking: " + outfile.getPath() ); - getLogger().debug( "compression: " + compress ); - jlink linker = new jlink(); - linker.setOutfile( outfile.getPath() ); - linker.setCompression( compress ); - if( haveMergeFiles() ) - { - getLogger().debug( "merge files: " + mergefiles.toString() ); - linker.addMergeFiles( mergefiles.list() ); - } - if( haveAddFiles() ) - { - getLogger().debug( "add files: " + addfiles.toString() ); - linker.addAddFiles( addfiles.list() ); - } - try - { - linker.link(); - } - catch( Exception ex ) - { - throw new TaskException( "Error", ex ); - } - } - - private boolean haveAddFiles() - throws TaskException - { - return haveEntries( addfiles ); - } - - private boolean haveEntries( Path p ) - throws TaskException - { - if( p == null ) - { - return false; - } - if( p.size() > 0 ) - { - return true; - } - return false; - } - - private boolean haveMergeFiles() - throws TaskException - { - return haveEntries( mergefiles ); - } -} - diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java deleted file mode 100644 index c1b33c9bb..000000000 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java +++ /dev/null @@ -1,469 +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.jlink; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.zip.CRC32; -import java.util.zip.Deflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -public class jlink extends Object -{ - - private String outfile = null; - - private ArrayList mergefiles = new ArrayList( 10 ); - - private ArrayList addfiles = new ArrayList( 10 ); - - private boolean compression = false; - - byte[] buffer = new byte[ 8192 ]; - - public static void main( String[] args ) - { - // jlink output input1 ... inputN - if( args.length < 2 ) - { - System.out.println( "usage: jlink output input1 ... inputN" ); - System.exit( 1 ); - } - jlink linker = new jlink(); - linker.setOutfile( args[ 0 ] ); - //To maintain compatibility with the command-line version, we will only add files to be merged. - for( int i = 1; i < args.length; i++ ) - { - linker.addMergeFile( args[ i ] ); - } - try - { - linker.link(); - } - catch( Exception ex ) - { - System.err.print( ex.getMessage() ); - } - } - - /** - * Determines whether output will be compressed. - * - * @param compress The new Compression value - */ - public void setCompression( boolean compress ) - { - this.compression = compress; - } - - /** - * The file that will be created by this instance of jlink. - * - * @param outfile The new Outfile value - */ - public void setOutfile( String outfile ) - { - if( outfile == null ) - { - return; - } - this.outfile = outfile; - } - - /** - * Adds a file to be added into the output. - * - * @param addfile The feature to be added to the AddFile attribute - */ - public void addAddFile( String addfile ) - { - if( addfile == null ) - { - return; - } - addfiles.add( addfile ); - } - - /** - * Adds several file to be added into the output. - * - * @param addfiles The feature to be added to the AddFiles attribute - */ - public void addAddFiles( String[] addfiles ) - { - if( addfiles == null ) - { - return; - } - for( int i = 0; i < addfiles.length; i++ ) - { - addAddFile( addfiles[ i ] ); - } - } - - /** - * Adds a file to be merged into the output. - * - * @param mergefile The feature to be added to the MergeFile attribute - */ - public void addMergeFile( String mergefile ) - { - if( mergefile == null ) - { - return; - } - mergefiles.add( mergefile ); - } - - /** - * Adds several files to be merged into the output. - * - * @param mergefiles The feature to be added to the MergeFiles attribute - */ - public void addMergeFiles( String[] mergefiles ) - { - if( mergefiles == null ) - { - return; - } - for( int i = 0; i < mergefiles.length; i++ ) - { - addMergeFile( mergefiles[ i ] ); - } - } - - /** - * Performs the linking of files. Addfiles are added to the output as-is. - * For example, a jar file is added to the output as a jar file. However, - * mergefiles are first examined for their type. If it is a jar or zip file, - * the contents will be extracted from the mergefile and entered into the - * output. If a zip or jar file is encountered in a subdirectory it will be - * added, not merged. If a directory is encountered, it becomes the root - * entry of all the files below it. Thus, you can provide multiple, disjoint - * directories, as addfiles: they will all be added in a rational manner to - * outfile. - * - * @exception Exception Description of Exception - */ - public void link() - throws Exception - { - ZipOutputStream output = new ZipOutputStream( new FileOutputStream( outfile ) ); - if( compression ) - { - output.setMethod( ZipOutputStream.DEFLATED ); - output.setLevel( Deflater.DEFAULT_COMPRESSION ); - } - else - { - output.setMethod( ZipOutputStream.STORED ); - } - Iterator merges = mergefiles.iterator(); - while( merges.hasNext() ) - { - String path = (String)merges.next(); - File f = new File( path ); - if( f.getName().endsWith( ".jar" ) || f.getName().endsWith( ".zip" ) ) - { - //Do the merge - mergeZipJarContents( output, f ); - } - else - { - //Add this file to the addfiles ArrayList and add it - //later at the top level of the output file. - addAddFile( path ); - } - } - Iterator adds = addfiles.iterator(); - while( adds.hasNext() ) - { - String name = (String)adds.next(); - File f = new File( name ); - if( f.isDirectory() ) - { - //System.out.println("in jlink: adding directory contents of " + f.getPath()); - addDirContents( output, f, f.getName() + '/', compression ); - } - else - { - addFile( output, f, "", compression ); - } - } - if( output != null ) - { - try - { - output.close(); - } - catch( IOException ioe ) - { - } - } - } - - /* - * Gets the name of an entry in the file. This is the real name - * which for a class is the name of the package with the class - * name appended. - */ - private String getEntryName( File file, String prefix ) - { - String name = file.getName(); - if( !name.endsWith( ".class" ) ) - { - // see if the file is in fact a .class file, and determine its actual name. - try - { - InputStream input = new FileInputStream( file ); - String className = ClassNameReader.getClassName( input ); - input.close(); - if( className != null ) - { - return className.replace( '.', '/' ) + ".class"; - } - } - catch( IOException ioe ) - { - } - } - System.out.println( "From " + file.getPath() + " and prefix " + prefix + ", creating entry " + prefix + name ); - return ( prefix + name ); - } - - /* - * Adds contents of a directory to the output. - */ - private void addDirContents( ZipOutputStream output, File dir, String prefix, boolean compress ) - throws IOException - { - String[] contents = dir.list(); - for( int i = 0; i < contents.length; ++i ) - { - String name = contents[ i ]; - File file = new File( dir, name ); - if( file.isDirectory() ) - { - addDirContents( output, file, prefix + name + '/', compress ); - } - else - { - addFile( output, file, prefix, compress ); - } - } - } - - /* - * Adds a file to the output stream. - */ - private void addFile( ZipOutputStream output, File file, String prefix, boolean compress ) - throws IOException - { - //Make sure file exists - long checksum = 0; - if( !file.exists() ) - { - return; - } - ZipEntry entry = new ZipEntry( getEntryName( file, prefix ) ); - entry.setTime( file.lastModified() ); - entry.setSize( file.length() ); - if( !compress ) - { - entry.setCrc( calcChecksum( file ) ); - } - FileInputStream input = new FileInputStream( file ); - addToOutputStream( output, input, entry ); - } - - /* - * A convenience method that several other methods might call. - */ - private void addToOutputStream( ZipOutputStream output, InputStream input, ZipEntry ze ) - throws IOException - { - try - { - output.putNextEntry( ze ); - } - catch( ZipException zipEx ) - { - //This entry already exists. So, go with the first one. - input.close(); - return; - } - int numBytes = -1; - while( ( numBytes = input.read( buffer ) ) > 0 ) - { - output.write( buffer, 0, numBytes ); - } - output.closeEntry(); - input.close(); - } - - /* - * Necessary in the case where you add a entry that - * is not compressed. - */ - private long calcChecksum( File f ) - throws IOException - { - BufferedInputStream in = new BufferedInputStream( new FileInputStream( f ) ); - return calcChecksum( in, f.length() ); - } - - /* - * Necessary in the case where you add a entry that - * is not compressed. - */ - private long calcChecksum( InputStream in, long size ) - throws IOException - { - CRC32 crc = new CRC32(); - int len = buffer.length; - int count = -1; - int haveRead = 0; - while( ( count = in.read( buffer, 0, len ) ) > 0 ) - { - haveRead += count; - crc.update( buffer, 0, count ); - } - in.close(); - return crc.getValue(); - } - - /* - * Actually performs the merging of f into the output. - * f should be a zip or jar file. - */ - private void mergeZipJarContents( ZipOutputStream output, File f ) - throws IOException - { - //Check to see that the file with name "name" exists. - if( !f.exists() ) - { - return; - } - ZipFile zipf = new ZipFile( f ); - Enumeration entries = zipf.entries(); - while( entries.hasMoreElements() ) - { - ZipEntry inputEntry = (ZipEntry)entries.nextElement(); - //Ignore manifest entries. They're bound to cause conflicts between - //files that are being merged. User should supply their own - //manifest file when doing the merge. - String inputEntryName = inputEntry.getName(); - int index = inputEntryName.indexOf( "META-INF" ); - if( index < 0 ) - { - //META-INF not found in the name of the entry. Go ahead and process it. - try - { - output.putNextEntry( processEntry( zipf, inputEntry ) ); - } - catch( ZipException ex ) - { - //If we get here, it could be because we are trying to put a - //directory entry that already exists. - //For example, we're trying to write "com", but a previous - //entry from another mergefile was called "com". - //In that case, just ignore the error and go on to the - //next entry. - String mess = ex.getMessage(); - if( mess.indexOf( "duplicate" ) >= 0 ) - { - //It was the duplicate entry. - continue; - } - else - { - //I hate to admit it, but we don't know what happened here. Throw the Exception. - throw ex; - } - } - InputStream in = zipf.getInputStream( inputEntry ); - int len = buffer.length; - int count = -1; - while( ( count = in.read( buffer, 0, len ) ) > 0 ) - { - output.write( buffer, 0, count ); - } - in.close(); - output.closeEntry(); - } - } - zipf.close(); - } - - /* - * A method that does the work on a given entry in a mergefile. - * The big deal is to set the right parameters in the ZipEntry - * on the output stream. - */ - private ZipEntry processEntry( ZipFile zip, ZipEntry inputEntry ) - throws IOException - { - /* - * First, some notes. - * On MRJ 2.2.2, getting the size, compressed size, and CRC32 from the - * ZipInputStream does not work for compressed (deflated) files. Those calls return -1. - * For uncompressed (stored) files, those calls do work. - * However, using ZipFile.getEntries() works for both compressed and - * uncompressed files. - * Now, from some simple testing I did, it seems that the value of CRC-32 is - * independent of the compression setting. So, it should be easy to pass this - * information on to the output entry. - */ - String name = inputEntry.getName(); - if( !( inputEntry.isDirectory() || name.endsWith( ".class" ) ) ) - { - try - { - InputStream input = zip.getInputStream( zip.getEntry( name ) ); - String className = ClassNameReader.getClassName( input ); - input.close(); - if( className != null ) - { - name = className.replace( '.', '/' ) + ".class"; - } - } - catch( IOException ioe ) - { - } - } - ZipEntry outputEntry = new ZipEntry( name ); - outputEntry.setTime( inputEntry.getTime() ); - outputEntry.setExtra( inputEntry.getExtra() ); - outputEntry.setComment( inputEntry.getComment() ); - outputEntry.setTime( inputEntry.getTime() ); - if( compression ) - { - outputEntry.setMethod( ZipEntry.DEFLATED ); - //Note, don't need to specify size or crc for compressed files. - } - else - { - outputEntry.setMethod( ZipEntry.STORED ); - outputEntry.setCrc( inputEntry.getCrc() ); - outputEntry.setSize( inputEntry.getSize() ); - } - return outputEntry; - } - -} -