Browse Source

JLink no longer needed as zipfileset and friends have surpassed all the functionality that JLink previous encompassed

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270446 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Donald 23 years ago
parent
commit
acde46cee6
6 changed files with 0 additions and 1590 deletions
  1. +0
    -116
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
  2. +0
    -210
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
  3. +0
    -469
      proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java
  4. +0
    -116
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
  5. +0
    -210
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
  6. +0
    -469
      proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java

+ 0
- 116
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java View File

@@ -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. <p>
*
* Extremely minimal constant pool implementation, mainly to support extracting
* strings from a class file.
*
* @author <a href="mailto:beard@netscape.com">Patrick C. Beard</a> .
*/
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;
}
}
}

}


+ 0
- 210
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java View File

@@ -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.
* <p>
*
* It is basically a wrapper for the jlink code written originally by <a
* href="mailto:beard@netscape.com">Patrick Beard</a> . The classes
* org.apache.tools.ant.taskdefs.optional.jlink.Jlink and
* org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader support this
* class.</p> <p>
*
* For example: <code>
* <pre>
* &lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;/&gt;
* &lt;mergefiles&gt;
* &lt;pathelement path=&quot;${build.dir}/mergefoo.jar&quot;/&gt;
* &lt;pathelement path=&quot;${build.dir}/mergebar.jar&quot;/&gt;
* &lt;/mergefiles&gt;
* &lt;addfiles&gt;
* &lt;pathelement path=&quot;${build.dir}/mac.jar&quot;/&gt;
* &lt;pathelement path=&quot;${build.dir}/pc.zip&quot;/&gt;
* &lt;/addfiles&gt;
* &lt;/jlink&gt;
* </pre> </code>
*
* @author <a href="mailto:matthew.k.heun@gaerospace.com">Matthew Kuperus Heun
* </a>
*/
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 );
}
}


+ 0
- 469
proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java View File

@@ -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;
}

}


+ 0
- 116
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java View File

@@ -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. <p>
*
* Extremely minimal constant pool implementation, mainly to support extracting
* strings from a class file.
*
* @author <a href="mailto:beard@netscape.com">Patrick C. Beard</a> .
*/
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;
}
}
}

}


+ 0
- 210
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java View File

@@ -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.
* <p>
*
* It is basically a wrapper for the jlink code written originally by <a
* href="mailto:beard@netscape.com">Patrick Beard</a> . The classes
* org.apache.tools.ant.taskdefs.optional.jlink.Jlink and
* org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader support this
* class.</p> <p>
*
* For example: <code>
* <pre>
* &lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;/&gt;
* &lt;mergefiles&gt;
* &lt;pathelement path=&quot;${build.dir}/mergefoo.jar&quot;/&gt;
* &lt;pathelement path=&quot;${build.dir}/mergebar.jar&quot;/&gt;
* &lt;/mergefiles&gt;
* &lt;addfiles&gt;
* &lt;pathelement path=&quot;${build.dir}/mac.jar&quot;/&gt;
* &lt;pathelement path=&quot;${build.dir}/pc.zip&quot;/&gt;
* &lt;/addfiles&gt;
* &lt;/jlink&gt;
* </pre> </code>
*
* @author <a href="mailto:matthew.k.heun@gaerospace.com">Matthew Kuperus Heun
* </a>
*/
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 );
}
}


+ 0
- 469
proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java View File

@@ -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;
}

}


Loading…
Cancel
Save