FileDocCategorySizeDatePackage
jlink.javaAPI DocApache Ant 1.7014941Wed Dec 13 06:16:20 GMT 2006org.apache.tools.ant.taskdefs.optional.jlink

jlink

public class jlink extends Object
jlink links together multiple .jar files.

(Omit source code)

Fields Summary
private String
outfile
private Vector
mergefiles
private Vector
addfiles
private boolean
compression
byte[]
buffer
Constructors Summary
Methods Summary
public voidaddAddFile(java.lang.String fileToAdd)
Adds a file to be added into the output.

param
fileToAdd the file to add to the output.

        if (fileToAdd == null) {
            return;
        }
        addfiles.addElement(fileToAdd);
    
public voidaddAddFiles(java.lang.String[] filesToAdd)
Adds several file to be added into the output.

param
filesToAdd an array of files to add to the output.

        if (filesToAdd == null) {
            return;
        }
        for (int i = 0; i < filesToAdd.length; i++) {
            addAddFile(filesToAdd[i]);
        }
    
private voidaddDirContents(java.util.zip.ZipOutputStream output, java.io.File dir, java.lang.String prefix, boolean compress)

        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);
            }
        }
    
private voidaddFile(java.util.zip.ZipOutputStream output, java.io.File file, java.lang.String prefix, boolean compress)

        //Make sure file exists
        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);
    
public voidaddMergeFile(java.lang.String fileToMerge)
Adds a file to be merged into the output.

param
fileToMerge the file to merge into the output.

        if (fileToMerge == null) {
            return;
        }
        mergefiles.addElement(fileToMerge);
    
public voidaddMergeFiles(java.lang.String[] filesToMerge)
Adds several files to be merged into the output.

param
filesToMerge an array of files to merge into the output.

        if (filesToMerge == null) {
            return;
        }
        for (int i = 0; i < filesToMerge.length; i++) {
            addMergeFile(filesToMerge[i]);
        }
    
private voidaddToOutputStream(java.util.zip.ZipOutputStream output, java.io.InputStream input, java.util.zip.ZipEntry ze)

        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();
    
private longcalcChecksum(java.io.File f)

        BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));

        return calcChecksum(in);
    
private longcalcChecksum(java.io.InputStream in)

        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();
    
private java.lang.StringgetEntryName(java.io.File file, java.lang.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.
            InputStream input = null;
            try {
                input = new FileInputStream(file);
                String className = ClassNameReader.getClassName(input);

                if (className != null) {
                    return className.replace('.", '/") + ".class";
                }
            } catch (IOException ioe) {
                //do nothing
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        //do nothing
                    }
                }
            }
        }
        System.out.println("From " + file.getPath() + " and prefix " + prefix
                           + ", creating entry " + prefix + name);
        return (prefix + name);
    
public voidlink()
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.

throws
Exception on error.

        ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outfile));

        if (compression) {
            output.setMethod(ZipOutputStream.DEFLATED);
            output.setLevel(Deflater.DEFAULT_COMPRESSION);
        } else {
            output.setMethod(ZipOutputStream.STORED);
        }

        Enumeration merges = mergefiles.elements();

        while (merges.hasMoreElements()) {
            String path = (String) merges.nextElement();
            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 Vector and add it
                //later at the top level of the output file.
                addAddFile(path);
            }
        }

        Enumeration adds = addfiles.elements();

        while (adds.hasMoreElements()) {
            String name = (String) adds.nextElement();
            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) {
                //do nothing
            }
        }
    
public static voidmain(java.lang.String[] args)
The command line entry point for jlink.

param
args an array of arguments

        // 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());
        }
    
private voidmergeZipJarContents(java.util.zip.ZipOutputStream output, java.io.File f)

        //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();
    
private java.util.zip.ZipEntryprocessEntry(java.util.zip.ZipFile zip, java.util.zip.ZipEntry inputEntry)

        /*
          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) {
                //do nothing
            }
        }
        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;
    
public voidsetCompression(boolean compress)
Determines whether output will be compressed.

param
compress if true use compression.

        this.compression = compress;
    
public voidsetOutfile(java.lang.String outfile)
The file that will be created by this instance of jlink.

param
outfile the file to create.


    // CheckStyle:VisibilityModifier OFF - bc

                          
        
        if (outfile == null) {
            return;
        }
        this.outfile = outfile;