Package com.simontuffs.onejar.ant

Source Code of com.simontuffs.onejar.ant.OneJarTask

/*
* Created on Jun 13, 2005
*
*/
package com.simontuffs.onejar.ant;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.FileScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.taskdefs.ManifestException;
import org.apache.tools.ant.taskdefs.Manifest.Attribute;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.zip.ZipOutputStream;

import com.simontuffs.onejar.Boot;

/**
* @author simon
* The One-Jar Ant task.  Extends <jar>
*
*/
public class OneJarTask extends Jar {
   
    public static final int BUFFER_SIZE = 8192;
    public static final String META_INF_MANIFEST = "META-INF/MANIFEST.MF";
    public static final String MAIN_MAIN_JAR = "main/main.jar";
    public static final String CLASS = ".class";
    public static final String NL = "\n";
   
    public static final String MAIN_CLASS = Attributes.Name.MAIN_CLASS.toString();
   
    protected Main main;
    protected MainJars mainJars;
    protected ZipFile onejar;
    protected File mainManifest;
    protected String oneJarMainClass;
    protected boolean manifestSet;
   
    public static class Main extends Task {
        protected List filesets = new ArrayList();
        protected File manifest;
        protected File jar;
        public void setManifest(File manifest) {
            this.manifest = manifest;
        }
        public void addFileSet(FileSet fileset) {
            if (jar != null)
                throw new BuildException("'jar' attribute is mutually exclusive to use of <fileset>");
            log("Main.addFileSet() ", Project.MSG_VERBOSE);
            filesets.add(fileset);
        }
        public void setJar(File main) {
            jar = main;
        }
    }
   
    public static class MainJars extends Task {
        protected List filesets = new ArrayList();
        protected String app;
        public void addFileSet(ZipFileSet fileset) {
            log("MainJar.addFileSet() ", Project.MSG_VERBOSE);
            filesets.add(fileset);
        }
    }

    public static class Lib extends Task {
        protected List filesets = new ArrayList();
        public void addFileSet(ZipFileSet fileset) {
            log("Lib.addFileSet() ", Project.MSG_VERBOSE);
            filesets.add(fileset);
        }
        public void addConfiguredClasspath(final Path classpath) {
            log("adding classpath: " + classpath, Project.MSG_VERBOSE);
            final Iterator pathIter = classpath.iterator();
            while(pathIter.hasNext()) {
                final Resource res = (Resource)pathIter.next();
                if(res instanceof FileResource) {
                    final FileResource fres = (FileResource)res;         
                    log("res.name: " + fres.getName()
                            + " res.exists: " + fres.isExists()
                            + " res.class: " + fres.getClass().getName()
                            + " res.file: " + fres.getFile()
                            , Project.MSG_DEBUG);
                    final File dir = fres.getFile().getParentFile();
                    final String name = fres.getFile().getName();
                    final ZipFileSet fileset = new ZipFileSet();
                    fileset.setProject(getProject());
                    fileset.setDir(dir);
                    fileset.createInclude().setName(name);
                    filesets.add(fileset);
                } else {
                    throw new BuildException("Not a file resource: " + res);
                }
            }         
        }
    }

    public static class Wrap extends Task {
        protected List filesets = new ArrayList();
        public void addFileSet(ZipFileSet fileset) {
            log("Wrap.addFileSet() ", Project.MSG_VERBOSE);
            filesets.add(fileset);
        }
    }
   
    public static class BinLib extends Task {
        protected List filesets = new ArrayList();
        public void addFileSet(ZipFileSet fileset) {
            log("BinLib.addFileSet() ", Project.MSG_VERBOSE);
            filesets.add(fileset);
        }
    }
   
    /**
     * Default constructor.
     */
    public OneJarTask() {
        super();
    }
   
    /**
     *  Constructor for use outside Ant: creates a wrapping project and gives it a name.
     */
    public OneJarTask(String project) {
        super();
        setTaskName("one-jar");
        setProject(new Project());
        getProject().setName(project);
    }
   
    public void setBootManifest(File manifest) {
        log("setBootManifest(" + manifest + ")", Project.MSG_VERBOSE);
        super.setManifest(manifest);
    }

    /**
     * Use <main manifest="file"> instead of this method.  This is here for
     * compatibility with the one-jar-macro.
     * @param manifest
     */
    public void setMainManifest(File manifest) {
        mainManifest = manifest;
        log("setMainManifest(" + manifest + ")", Project.MSG_VERBOSE);
    }
   
    public void setOneJarMainClass(String main) {
        oneJarMainClass = main;
    }

    public void setOneJarBoot(ZipFile jar) {
        log("setOneJarBoot(" + jar + ")", Project.MSG_VERBOSE);
        this.onejar = jar;
    }

    public void addBoot(ZipFileSet files) {
        log("addBoot()", Project.MSG_VERBOSE);
        super.addFileset(files);
    }
   
    public void addMain(Main main) {
        log("addMain()", Project.MSG_VERBOSE);
        this.main =  main;
    }
   
    public void addConfiguredLib(Lib lib) {
        log("addLib()", Project.MSG_VERBOSE);
        Iterator iter = lib.filesets.iterator();
        while (iter.hasNext()) {
            ZipFileSet fileset = (ZipFileSet)iter.next();
            fileset.setPrefix("lib/");
            super.addFileset(fileset);
        }
    }
   
    public void addConfiguredManifest(Manifest newManifest) throws ManifestException {
        super.addConfiguredManifest(newManifest);
        manifestSet = true;
    }
   
    public void addConfiguredMainJars(MainJars jars) {
      this.mainJars = jars;
        log("addMainJar()", Project.MSG_VERBOSE);
        Iterator iter = jars.filesets.iterator();
        while (iter.hasNext()) {
            ZipFileSet fileset = (ZipFileSet)iter.next();
            fileset.setPrefix("main/");
            super.addFileset(fileset);
        }
    }
   
    public void addConfiguredWrap(Wrap lib) {
        log("addWrap()", Project.MSG_VERBOSE);
        Iterator iter = lib.filesets.iterator();
        while (iter.hasNext()) {
            ZipFileSet fileset = (ZipFileSet)iter.next();
            fileset.setPrefix("wrap/");
            super.addFileset(fileset);
        }
    }
   
    public void addConfiguredBinLib(BinLib lib) {
        log("addBinLib()", Project.MSG_VERBOSE);
        Iterator iter = lib.filesets.iterator();
        while (iter.hasNext()) {
            ZipFileSet fileset = (ZipFileSet)iter.next();
            fileset.setPrefix("binlib/");
            super.addFileset(fileset);
        }
    }
   
   
    protected class PipedThread extends Thread {
        protected boolean done = false;
        protected PipedInputStream pin = new PipedInputStream();
        protected PipedOutputStream pout = new PipedOutputStream();
       
        protected Set entries = new HashSet();
        public PipedThread() {
            try {
                pin.connect(pout);
            } catch (IOException iox) {
                throw new BuildException(iox);
            }
        }
       
    }

    /**
     * Convert a fileset into an input stream which appears as though it was
     * read from a Zip file.
     * @author simon
     *
     */
    protected class FileSetPump extends PipedThread {
        protected String target;
       
        public FileSetPump(String target) {
            this.target = target;
        }
       
        public void run() {
            // Create the main/main.jar entry in the output file, and suck in
            // all <filesets> from <main>. 
            // TODO: Ignore duplicates (first takes precedence).
          if (main != null) {
              Iterator iter = main.filesets.iterator();
              java.util.zip.ZipOutputStream zout = new java.util.zip.ZipOutputStream(pout);
             
             
              try {
                  // Write the manifest file.
                  ZipEntry m = new ZipEntry(META_INF_MANIFEST);
                  zout.putNextEntry(m);
                  if (main.manifest != null) {
                      copy(new FileInputStream(main.manifest), zout, true);
                  } else if (mainManifest != null) {
                      copy(new FileInputStream(mainManifest), zout, true);
                    }
                  zout.closeEntry();
                  // Now the rest of the main.jar entries
                  while (iter.hasNext()) {
                      FileSet fileset = (FileSet)iter.next();
                      FileScanner scanner = fileset.getDirectoryScanner(getProject());
                      String[] files = scanner.getIncludedFiles();
                      File basedir = scanner.getBasedir();
                      for (int i=0; i<files.length; i++) {
                          String file = files[i].replace('\\', '/');
                          if (entries.contains(file)) {
                              log("Duplicate entry " + target + " (ignored): " + file, Project.MSG_WARN);
                              continue;
                          }
                          entries.add(file);
                          // Add any directory entries that have not already been added.
                          String p = new File(file).getParent();
                          if (p != null) {
                            String dirs = p.replace('\\', '/');
                            if (!entries.contains(dirs)) {
                              String toks[] = dirs.split("/");
                              String dir = "";
                              for (int d=0; d<toks.length; d++) {
                                dir += toks[d] + "/";
                                if (!entries.contains(dir)) {
                                  ZipEntry ze = new ZipEntry(dir);
                                  zout.putNextEntry(ze);
                                            // Suppress FindBugs AM warning.
                                            zout.flush();
                                  zout.closeEntry();
                                  entries.add(dir);
                                }
                              }
                              entries.add(dir);
                            }
                          }
                         
                          ZipEntry ze = new ZipEntry(file);
                          zout.putNextEntry(ze);
                          log("processing " + file, Project.MSG_DEBUG);
                          FileInputStream fis = new FileInputStream(new File(basedir, file));
                          copy(fis, zout, true);
                          zout.closeEntry();
                      }
                  }
                  zout.close();
                    synchronized(this) {
                        done = true;
                        notify();
                    }
              } catch (IOException iox) {
                  throw new BuildException(iox);
              }
          }
        }
    }
   
    protected void includeZip(ZipFile zip, ZipOutputStream zOut) {
        try {
            Enumeration entries = zip.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry)entries.nextElement();
                if (entry.getName().endsWith(CLASS) || entry.getName().equals(".version")) {
                    log("ZipPump: " + entry.getName(), Project.MSG_DEBUG);
                    super.zipFile(zip.getInputStream(entry), zOut, entry.getName(), System.currentTimeMillis(), null, ZipFileSet.DEFAULT_FILE_MODE);
                }
            }
        } catch (IOException iox) {
            throw new BuildException(iox);
        }
    }

    protected byte buf[] = new byte[BUFFER_SIZE];
    protected void copy(InputStream is, OutputStream os, boolean closein) throws IOException {
        int len = -1;
        while ((len = is.read(buf)) >= 0) {
            os.write(buf, 0, len);
        }
        if (closein) is.close();
    }
   
    protected void copy(String s, OutputStream os) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
        copy(bais, os, true);
    }
   
    public void setManifest(File manifestFile) {
        super.setManifest(manifestFile);
        manifestSet = true;
    }
   
    protected void checkMain() {
        if (mainJars == null && main == null)
            throw new BuildException("No <main> or <mainjars> element found in the <one-jar> task!");
    }
   
    protected void checkManifest() {
        if (!manifestSet)
            log("No 'manifest' attribute was specified for the <one-jar> task, a default manifest will be generated.", Project.MSG_WARN);
    }
   
    protected void addOneJarBoot(ZipOutputStream zOut) throws IOException {
        // BUG-2674591: filesetmanifest attribute leads to null zOut: ignore.
        if (zOut ==null)
            return;
        // One-jar bootstrap files
        if (onejar != null) {
            includeZip(onejar, zOut);
        } else {
            // Pick up default one-jar boot files as a resource relative to
            // this class.
            String ONE_JAR_BOOT = "one-jar-boot.jar";
            InputStream is = OneJarTask.class.getResourceAsStream(ONE_JAR_BOOT);
            if (is == null)
                throw new IOException("Unable to load default " + ONE_JAR_BOOT + ": consider using the <one-jar onejarboot=\"...\"> option.");
            // Pull the manifest out and use it.
            JarInputStream jis = new JarInputStream(is);
            Manifest manifest = new Manifest();
            java.util.jar.Manifest jmanifest = jis.getManifest();
            java.util.jar.Attributes jattributes = jmanifest.getMainAttributes();
            try {
                // Specify our Created-By and Main-Class attributes as overrides.
                manifest.addConfiguredAttribute(new Attribute("Created-By", "One-Jar 0.98 Ant taskdef"));
                manifest.addConfiguredAttribute(new Attribute(MAIN_CLASS, jattributes.getValue(MAIN_CLASS)));
                if (oneJarMainClass != null) {
                    manifest.addConfiguredAttribute(new Attribute(Boot.ONE_JAR_MAIN_CLASS, oneJarMainClass));
                }
                super.addConfiguredManifest(manifest);
            } catch (ManifestException mx) {
                throw new BuildException(mx);
            }
            super.initZipOutputStream(zOut);
            ZipEntry entry = jis.getNextEntry();
            while (entry != null) {
                if (entry.getName().endsWith(CLASS) || entry.getName().equals(".version") || entry.getName().endsWith("license.txt")) {
                    log("entry=" + entry.getName(), Project.MSG_DEBUG);
                    zOut.putNextEntry(new org.apache.tools.zip.ZipEntry(entry));
                    copy(jis, zOut, false);
                }
                entry = jis.getNextJarEntry();
            }
           
        }
    }
   
    protected void addMain(ZipOutputStream zOut) throws IOException {
        // Already constructed?
        if (main == null || main.jar != null)
            return;
        // Assemble main/main.jar
        FileSetPump pump = new FileSetPump(MAIN_MAIN_JAR);
        pump.start();
        super.zipFile(pump.pin, zOut, MAIN_MAIN_JAR, System.currentTimeMillis(), null, ZipFileSet.DEFAULT_FILE_MODE);
       
    }
   
    protected void initZipOutputStream(ZipOutputStream zOut) throws IOException {
       
        // Sanity Checks.
        checkMain();
        checkManifest();

        // Add com.simontuffs.onejar classes
        addOneJarBoot(zOut);
       
        // Add main/main.jar
        addMain(zOut);
       
    }
   
    public void execute() throws BuildException {
        log("execute()", Project.MSG_VERBOSE);
        // First include a main.jar if specified.
        if (main != null && main.jar != null) {
            ZipFileSet fs = new ZipFileSet();
            fs.setProject(getProject());
            fs.setFile(main.jar);
            fs.setPrefix("main/");
            //System.out.println("main.jar fs=" + fs);
            super.addFileset(fs);
        }
       
        // Then, add all files to the final jar.
        super.execute();
    }
   
   
    protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, long lastModified, File fromArchive,
            int mode) throws IOException {
        if (vPath.equals(Boot.MAIN_JAR) && (main == null || main.jar == null)) {
            log("zipFile(): unable to build " + Boot.MAIN_JAR, Project.MSG_VERBOSE);
        } else {
            super.zipFile(is, zOut, vPath, lastModified, fromArchive, mode);
        }
    }
}
TOP

Related Classes of com.simontuffs.onejar.ant.OneJarTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.