Package org.moxie.ant

Source Code of org.moxie.ant.GenJar$ExcludedResolverException

/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000, 2001, 2002, 2003 Jesse Stockall.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
*    Foundation" must not be used to endorse or promote products derived
*    from this software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
*    nor may "Apache" appear in their names without prior written
*    permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
*/
package org.moxie.ant;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Manifest;
import org.apache.tools.ant.taskdefs.Manifest.Section;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.moxie.MoxieException;
import org.moxie.utils.StringUtils;


/**
* Driver class for the <genjar> task.
* <p>
*
* This class is instantiated when Ant encounters the &lt;genjar&gt; element.
*
* @author Original Code: <a href="mailto:jake@riggshill.com">John W. Kohler</a>
* @author Jesse Stockall
* @version $Revision: 1.11 $ $Date: 2003/03/06 01:22:00 $
*/
public class GenJar extends Task {

  protected List<JarSpec> jarSpecs = new ArrayList<JarSpec>();

  private List<LibrarySpec> libraries = new ArrayList<LibrarySpec>();

  protected Manifest mft = Manifest.getDefaultManifest();

  protected Path classpath = null;
 
  protected Path librarypath = null;

  private ClassFilter classFilter = null;

  protected File destFile = null;

  protected Set<String> resolvedLocal = new TreeSet<String>();

  private List<PathResolver> resolvers = new ArrayList<PathResolver>();

  private Set<String> resolved = new TreeSet<String>();
 
  protected Set<String> exportedPackages = new TreeSet<String>();
 
  private Logger logger = null;
 
  protected String version;
 
  boolean excludeClasspathJars;
 
  String excludes;

  /**
   * main execute for genjar
   * <ol>
   * <li>setup logger
   * <li>ensure classpath is setup (with any additions from sub-elements
   * <li>initialize file resolvers
   * <li>initialize the manifest
   * <li>resolve resource file paths resolve class file paths generate
   * dependency graphs for class files and resolve those paths check for
   * duplicates
   * <li>generate manifest entries for all candidate files
   * <li>build jar
   * </ol>
   *
   *
   * @throws BuildException
   *             Oops!
   */
  public void execute() throws BuildException {
    logger = new Logger(getProject());
    if (classFilter == null) {
      classFilter = new ClassFilter(logger);
    }

    //
    // set up the classpath & resolvers - file/jar/zip
    //
    try {
      if (classpath == null) {
        classpath = new Path(getProject());
        classpath.addExisting(Path.systemClasspath);
      }
      librarypath = new Path(getProject());

      for (LibrarySpec lib : libraries) {
        Path p = lib.getPathElement();
        if (p != null) {
          librarypath.addExisting(p);
        }
      }
      logger.verbose("Initializing Path Resolvers");
      logger.verbose("Classpath:" + classpath);
      logger.verbose("Librarypath:" + librarypath);
      initPathResolvers();
    } catch (IOException ioe) {
      throw new MoxieException("Unable to process classpath: " + ioe,
          getLocation());
    }

    //
    // run over all the resource and class specifications
    // given in the project file
    // resources are resolved to full path names while
    // class specifications are exploded to dependency
    // graphs - when done, getJarEntries() returns a list
    // of all entries generated by this JarSpec
    //
    List<JarEntrySpec> entries = new ArrayList<JarEntrySpec>();

    for (JarSpec js : jarSpecs) {
      try {
        js.resolve(this);
      } catch (FileNotFoundException ioe) {
        throw new ResolutionFailedException(js.getName(), ioe.getMessage());
      } catch (IOException ioe) {
        throw new MoxieException("Unable to resolve: " + js.getName()
            + "\nMSG=" + ioe.getMessage(), ioe, getLocation());
      }
      //
      // before adding a new jarspec - see if it already exists
      // first entry added to jar always wins
      //
      for (JarEntrySpec spec : js.getJarEntries()) {
        if (!entries.contains(spec)) {
          entries.add(spec);
        } else {
          logger.verbose("Duplicate (ignored): " + spec.getJarName());
        }
      }
    }
    //
    // we have all the entries we're gonna jar - the manifest
    // must be fully built prior to jar generation, so run over
    // each entry and and add it to the manifest
    //
    for (JarEntrySpec jes : entries) {
      if (jes.getSourceFile() == null) {
        try {
          InputStream is = resolveEntry(jes);
          if (is != null) {
            is.close();
          }
        } catch (IOException ioe) {
          throw new MoxieException(
              "Error while generating manifest entry for: "
                  + jes.toString(), ioe, getLocation());
        }
      }
    }

    JarOutputStream jout = null;
    InputStream is = null;
    try {
      jout = new JarOutputStream(new FileOutputStream(destFile), createJarManifest());
      writeJarEntries(jout);
     
      for (JarEntrySpec jes : entries) {
        JarEntry entry = new JarEntry(jes.getJarName());
        is = resolveEntry(jes);

        if (is == null) {
          logger.error("Unable to locate previously resolved resource");
          logger.error("       Jar Name:" + jes.getJarName());
          logger.error("Resolved Source:" + jes.getSourceFile());
          try {
            if (jout != null) {
              jout.close();
            }
          } catch (IOException ioe) {
          }
          throw new MoxieException("Jar component not found: "
              + jes.getJarName(), getLocation());
        }
        jout.putNextEntry(entry);
        byte[] buff = new byte[4096]; // stream copy buffer
        int len;
        while ((len = is.read(buff, 0, buff.length)) != -1) {
          jout.write(buff, 0, len);
        }
        jout.closeEntry();
        is.close();

        logger.verbose("Added: " + jes.getJarName());
      }
    } catch (IOException ioe) {
      throw new MoxieException("Unable to create jar: "
          + destFile.getName(), ioe, getLocation());
    } finally {
      try {
        if (is != null) {
          is.close();
        }
      } catch (IOException ioe) {
      }
      try {
        if (jout != null) {
          jout.close();
        }
      } catch (IOException ioe) {
      }
    }
   
    // Close all the resolvers
    for (PathResolver resolver : resolvers) {
      try {
        resolver.close();
      } catch (IOException ioe) {
      }
    }
  }
 
  protected void writeJarEntries(JarOutputStream jos) {
  }
 
  /**
   * Sets the classpath attribute.
   *
   * @param s
   *            The new classpath.
   */
  public void setClasspath(Path s) {
    createClasspath().append(s);
  }

  /**
   * Builds the classpath.
   *
   * @return A <path>
   *
   *         element.
   */
  public Path createClasspath() {
    if (classpath == null) {
      classpath = new Path(getProject());
    }
    return classpath;
  }

  /**
   * Sets the Classpathref attribute.
   *
   * @param r
   *            The new classpathRef.
   */
  public void setClasspathRef(Reference r) {
    createClasspath().setRefid(r);
  }

  /**
   * Builds a <class> element.
   *
   * @return A <class> element.
   */
  public ClassSpec createClass() {
    ClassSpec cs = new ClassSpec(getProject());
    jarSpecs.add(cs);
    return cs;
  }

  /**
   * Builds a manifest element.
   *
   * @return A <manifest> element.
   */
  public Manifest createManifest() {
    return mft;
  }
 
  @SuppressWarnings("unchecked")
  private java.util.jar.Manifest createJarManifest() {
    java.util.jar.Manifest newManifest = new java.util.jar.Manifest();
    newManifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
   
    Section mainSection = mft.getMainSection();
    Enumeration<String> mainAttributes = mainSection.getAttributeKeys()
    while (mainAttributes.hasMoreElements()) {
      String aname = mainAttributes.nextElement();
      String avalue = mainSection.getAttributeValue(aname);
      newManifest.getMainAttributes().putValue(aname, avalue);
    }
   
    // OSGI Export-Package
    if (!StringUtils.isEmpty(version)) {
      String vString = MessageFormat.format(";version=\"{0}\",", version);
      StringBuilder packages = new StringBuilder();
      for (String packageName : exportedPackages) {
        packages.append(packageName);
        packages.append(vString);
      }
      if (packages.length() > 0) {
        packages.setLength(packages.length() - 1);
        newManifest.getMainAttributes().putValue("Export-Package", packages.toString());
      }
    }

//    for (Map.Entry<Object, Object> entry : newManifest.getMainAttributes().entrySet()) {
//      System.out.println(entry.getKey() + "=" + entry.getValue());
//    }

    Enumeration<String> sections = mft.getSectionNames();
    while (sections.hasMoreElements()) {
      String sname = sections.nextElement();
      Section section = mft.getSection(sname);
     
      Attributes newAttributes = new Attributes();
      newManifest.getEntries().put(sname, newAttributes);
     
      Enumeration<String> attributes = section.getAttributeKeys()
      while (attributes.hasMoreElements()) {
        String aname = attributes.nextElement();
        String avalue = section.getAttributeValue(aname);
        newAttributes.putValue(aname, avalue);
      }
     
//      for (Map.Entry<Object, Object> entry : newManifest.getAttributes(sname).entrySet()) {
//        System.out.println(entry.getKey() + "=" + entry.getValue());
//      }
    }
   
    return newManifest;
  }

  /**
   * Builds a resource element.
   *
   * @return A <resource> element.
   */
  public Resource createResource() {
    Resource rsc = new Resource(getProject());
    jarSpecs.add(rsc);
    return rsc;
  }

  /**
   * Builds a classfilter element.
   *
   * @return A <classfilter> element.
   */
  public ClassFilter createClassfilter() {
    if (classFilter == null) {
      classFilter = new ClassFilter(new Logger(getProject()));
    }
    return classFilter;
  }

  /**
   * Builds a library element.
   *
   * @return A <library> element.
   */
  public LibrarySpec createLibrary() {
    LibrarySpec lspec = new LibrarySpec(getProject().getBaseDir(),
        new Path(getProject()));
    jarSpecs.add(lspec);
    libraries.add(lspec);
    return lspec;
  }

  /**
   * Sets the name of the jar file to be created.
   *
   * @param destFile
   *            The new destfile value
   */
  public void setDestfile(File destFile) {
    this.destFile = destFile;
  }

  /**
   * Iterate through the classpath and create an array of all the
   * <code>PathResolver</code>s
   *
   * @throws IOException
   *             Description of the Exception
   */
  private void initPathResolvers() throws IOException {
    // classes classpath can be excluded if class source is jar
    initPathResolvers(classpath, excludeClasspathJars);
    // classes on the library path are never excluded
    initPathResolvers(librarypath, false);
  }
 
  private void initPathResolvers(Path path, boolean excludeJars) throws IOException {
    for (String pc : path.list()) {
      File f = new File(pc);
      if (!f.exists()) {
        continue;
      }
      PathResolver resolver = null;
      if (f.isDirectory()) {
        resolver = new FileResolver(f, logger);
      } else if (f.getName().toLowerCase().endsWith(".jar")) {
        resolver = new JarResolver(f, excludeJars, logger);
      } else if (f.getName().toLowerCase().endsWith(".zip")) {
        resolver = new ZipResolver(f, logger);
      } else {
        throw new MoxieException(f.getName()
            + " is not a valid classpath component", getLocation());
      }
      logger.debug("added " + resolver);
      resolvers.add(resolver);
    }
  }

  /**
   * Description of the Method
   *
   * @param spec
   *            Description of the Parameter
   * @return Description of the Return Value
   * @throws IOException
   *             Description of the Exception
   */
  InputStream resolveEntry(JarEntrySpec spec) throws IOException {
    InputStream is = null;
    for (PathResolver resolver : resolvers) {
      is = resolver.resolve(spec);
      if (is != null) {
        if (resolver instanceof FileResolver) {
          // keep track of class files and packages added from output folders
          if (spec.getJarName().endsWith(".class")) {
            String className = spec.getJarName();
            resolvedLocal.add(className);
           
            if (className.lastIndexOf('/') > -1) {
              String packageName = className.substring(0, className.lastIndexOf('/'));           
              exportedPackages.add(packageName);
            }
          }
        }
        return is;
      }
    }
    return null;
  }

  /**
   * Resolves a partial file name against the classpath elements
   *
   * @param cname
   *            Description of the Parameter
   * @return An InputStream open on the named file or null
   * @throws IOException
   *             Description of the Exception
   */
  InputStream resolveEntry(String cname) throws IOException, ExcludedResolverException {
    InputStream is = null;

    for (PathResolver resolver : resolvers) {
      is = resolver.resolve(cname);
      if (is != null) {
        if (resolver.isExcluded()) {
          is.close();
          throw new ExcludedResolverException(resolver.toString());
        }
        return is;
      }
    }
    return null;
  }

  /**
   * Generates a list of all classes upon which the list of classes depend.
   *
   * @param entries
   *            List of <code>JarEntrySpec</code>s used as a list of class
   *            names from which to start.
   * @exception IOException
   *                If there's an error reading a class file
   */
  void generateDependencies(List<JarEntrySpec> entries) throws IOException {
    Set<String> dependents = new TreeSet<String>();

    Iterator<JarEntrySpec> itr = entries.iterator();
    while (itr.hasNext()) {
      JarEntrySpec js = itr.next();
      if (!generateClassDependencies(js.getJarName(), dependents)) {
        // class is located in an excluded source, exclude entry
        itr.remove();
      }
    }

    for (String dependent : dependents) {
      entries.add(new JarEntrySpec(dependent, null));
    }
  }

  /**
   * Generates a list of classes upon which the named class is dependent.
   *
   * @param classes
   *            A List into which the class names are placed
   * @param classFileName
   *            Description of the Parameter
   * @throws IOException
   *             Description of the Exception
   * @return true if the class should be kept
   */
  boolean generateClassDependencies(String classFileName, Set<String> classes)
      throws IOException {
    if (!resolved.contains(classFileName)) {
      resolved.add(classFileName);
     
      InputStream is = null;
      try {     
        is = resolveEntry(classFileName);
      } catch (ExcludedResolverException e) {
        // class is located in an excluded source
        // remove from entry list
        logger.debug(MessageFormat.format("{0} is located in {1}", classFileName, e.getMessage()));
        return false;
      }

      if (is == null) {
        throw new FileNotFoundException(classFileName);
      }
     
      List<String> referenced = ClassUtil.getDependencies(is);

      for (String name : referenced) {
        String cname = name + ".class";

        if (!classFilter.include(cname) || resolved.contains(cname)) {
          continue;
        }

        classes.add(cname);
        if (!generateClassDependencies(cname, classes)) {
          // dependent class is located in an excluded source
          // remove from list
          classes.remove(cname);
        }
      }
      is.close();
    }
    return true;
  }
 
  private static class ExcludedResolverException extends Exception {
   
    private static final long serialVersionUID = 1L;

    public ExcludedResolverException(String source) {
      super(source);
    }
  }
}
TOP

Related Classes of org.moxie.ant.GenJar$ExcludedResolverException

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.