Java/File Input Output/Jar File

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Содержание

A class to find resources in the classpath by their mime-type specified in the MANIFEST.

  
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* $Id$ */

import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
 * A class to find resources in the classpath by their mime-type specified in
 * the MANIFEST.
 * <p>
 * This class searches for content entries in all META-INF/MANIFEST.MF files. It
 * will find files with a given Content-Type: attribute. This allows to add
 * arbitrary resources by content-type just by creating a JAR wrapper and adding
 * them to the classpath.
 * <p>
 * Example:<br>
 * 
 * <pre>
 * Name: test.txt
 * Content-Type: text/plain
 * </pre>
 */
public final class ClasspathResource {
    /**
     * Actual Type: Map&lt;String,List&lt;URL&gt;&gt;.
     */
    private final Map contentMappings;
    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
    private static final String CONTENT_TYPE_KEY = "Content-Type";
    private static ClasspathResource classpathResource;
    private ClasspathResource() {
        contentMappings = new HashMap();
        loadManifests();
    }
    /**
     * Retrieve the singleton instance of this class.
     * 
     * @return the ClassPathResource instance.
     */
    public static synchronized ClasspathResource getInstance() {
        if (classpathResource == null) {
            classpathResource = new ClasspathResource();
        }
        return classpathResource;
    }
    /* Actual return type: Set<ClassLoader> */
    private Set getClassLoadersForResources() {
        Set v = new HashSet();
        try {
            ClassLoader l = ClassLoader.getSystemClassLoader();
            if (l != null) {
                v.add(l);
            }
        } catch (SecurityException e) {
            // Ignore
        }
        try {
            ClassLoader l = Thread.currentThread().getContextClassLoader();
            if (l != null) {
                v.add(l);
            }
        } catch (SecurityException e) {
            // Ignore
        }
        try {
            ClassLoader l = ClasspathResource.class.getClassLoader();
            if (l != null) {
                v.add(l);
            }
        } catch (SecurityException e) {
            // Ignore
        }
        return v;
    }
    private void loadManifests() {
        Enumeration e;
        try {
            Iterator it = getClassLoadersForResources().iterator();
            while (it.hasNext()) {
                ClassLoader classLoader = (ClassLoader) it.next();
                e = classLoader.getResources(MANIFEST_PATH);
                while (e.hasMoreElements()) {
                    final URL u = (URL) e.nextElement();
                    try {
                        final Manifest manifest = new Manifest(u.openStream());
                        final Map entries = manifest.getEntries();
                        final Iterator entrysetiterator = entries.entrySet()
                                .iterator();
                        while (entrysetiterator.hasNext()) {
                            final Map.Entry entry = (Map.Entry) entrysetiterator
                                    .next();
                            final String name = (String) entry.getKey();
                            final Attributes attributes = (Attributes) entry
                                    .getValue();
                            final String contentType = attributes
                                    .getValue(CONTENT_TYPE_KEY);
                            if (contentType != null) {
                                addToMapping(contentType, name, classLoader);
                            }
                        }
                    } catch (IOException io) {
                        // TODO: Log.
                    }
                }
            }
        } catch (IOException io) {
            // TODO: Log.
        }
    }
    private void addToMapping(final String contentType, final String name,
            final ClassLoader classLoader) {
        List existingFiles = (List) contentMappings.get(contentType);
        if (existingFiles == null) {
            existingFiles = new Vector();
            contentMappings.put(contentType, existingFiles);
        }
        final URL url = classLoader.getResource(name);
        if (url != null) {
            existingFiles.add(url);
        }
    }
    /**
     * Retrieve a list of resources known to have the given mime-type.
     * 
     * @param mimeType
     *            the mime-type to search for.
     * @return a List&lt;URL&gt;, guaranteed to be != null.
     */
    public List listResourcesOfMimeType(final String mimeType) {
        final List content = (List) contentMappings.get(mimeType);
        if (content == null) {
            return Collections.EMPTY_LIST;
        } else {
            return content;
        }
    }
}
////////////////
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* $Id: $ */
package org.apache.xmlgraphics.util;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
 * Test for the Service class.
 */
public class ClasspathResourceTest extends TestCase {
    /**
     * Tests whether the file /sample.txt with mime-type text/plain exists.
     * 
     * @throws Exception
     *             in case of an error
     */
    public void testSampleResource() throws Exception {
        final List list = ClasspathResource.getInstance()
                .listResourcesOfMimeType("text/plain");
        boolean found = false;
        final Iterator i = list.iterator();
        while (i.hasNext()) {
            final URL u = (URL) i.next();
            if (u.getPath().endsWith("sample.txt")) {
                found = true;
            }
        }
        assertTrue(found);
    }
    /**
     * Tests the mode where Service returns class names.
     * 
     * @throws Exception
     *             in case of an error
     */
    public void testNonexistingResource() throws Exception {
        final List list = ClasspathResource.getInstance()
                .listResourcesOfMimeType("nota/mime-type");
        assertTrue(list.isEmpty());
    }
}





Add a jar entry to the deployment archive

 
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
/**
 * A collection of jar utilities
 * 
 * @author thomas.diesler@jboss.org
 * @version $Revision: 81011 $
 */
public class JarUtils {
  /**
   * Add jar contents to the deployment archive under the given prefix
   */
  public static String[] addJar(JarOutputStream outputStream, String prefix, File jar)
      throws IOException {
    ArrayList tmp = new ArrayList();
    FileInputStream fis = new FileInputStream(jar);
    JarInputStream jis = new JarInputStream(fis);
    JarEntry entry = jis.getNextJarEntry();
    while (entry != null) {
      if (entry.isDirectory() == false) {
        String entryName = prefix + entry.getName();
        tmp.add(entryName);
        addJarEntry(outputStream, entryName, jis);
      }
      entry = jis.getNextJarEntry();
    }
    jis.close();
    String[] names = new String[tmp.size()];
    tmp.toArray(names);
    return names;
  }
  /**
   * Add a jar entry to the deployment archive
   */
  public static void addJarEntry(JarOutputStream outputStream, String entryName,
      InputStream inputStream) throws IOException {
    outputStream.putNextEntry(new JarEntry(entryName));
    copyStream(outputStream, inputStream);
  }
  /**
   * Copies the input stream to the output stream
   */
  public static void copyStream(OutputStream outputStream, InputStream inputStream)
      throws IOException {
    byte[] bytes = new byte[4096];
    int read = inputStream.read(bytes, 0, 4096);
    while (read > 0) {
      outputStream.write(bytes, 0, read);
      read = inputStream.read(bytes, 0, 4096);
    }
  }
}





Add jar contents to the deployment archive under the given prefix

 
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
/**
 * A collection of jar utilities
 * 
 * @author thomas.diesler@jboss.org
 * @version $Revision: 81011 $
 */
public class JarUtils {
  /**
   * Add jar contents to the deployment archive under the given prefix
   */
  public static String[] addJar(JarOutputStream outputStream, String prefix, File jar)
      throws IOException {
    ArrayList tmp = new ArrayList();
    FileInputStream fis = new FileInputStream(jar);
    JarInputStream jis = new JarInputStream(fis);
    JarEntry entry = jis.getNextJarEntry();
    while (entry != null) {
      if (entry.isDirectory() == false) {
        String entryName = prefix + entry.getName();
        tmp.add(entryName);
        addJarEntry(outputStream, entryName, jis);
      }
      entry = jis.getNextJarEntry();
    }
    jis.close();
    String[] names = new String[tmp.size()];
    tmp.toArray(names);
    return names;
  }
  /**
   * Add a jar entry to the deployment archive
   */
  public static void addJarEntry(JarOutputStream outputStream, String entryName,
      InputStream inputStream) throws IOException {
    outputStream.putNextEntry(new JarEntry(entryName));
    copyStream(outputStream, inputStream);
  }
  /**
   * Copies the input stream to the output stream
   */
  public static void copyStream(OutputStream outputStream, InputStream inputStream)
      throws IOException {
    byte[] bytes = new byte[4096];
    int read = inputStream.read(bytes, 0, 4096);
    while (read > 0) {
      outputStream.write(bytes, 0, read);
      read = inputStream.read(bytes, 0, 4096);
    }
  }
}





class for exploding jar/zip files onto the file system

  
/*******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  IBM Corporation - initial API and implementation
 *******************************************************************************/
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
 * class for exploding jar/zip files onto the file system
 * 
 * @author Barry Feigenbaum
 */
public class ZipExploder {
  /**
   * create a zip exploder for unpacking .jar/.zip files
   */
  public ZipExploder() {
    this(false);
  }
  /**
   * create a zip exploder for unpacking .jar/.zip files onto the file system
   * 
   * @param verbose -
   *          set to <code>true</code> for verbose mode
   */
  public ZipExploder(boolean verbose) {
    setVerbose(verbose);
  }
  /**
   * create a zip exploder for unpacking .jar/.zip files onto the file system
   * 
   * @param verbose -
   *          set to <code>true</code> for verbose mode
   * @param sorted -
   *          set to <code>true</code> for sorted file mode
   */
  public ZipExploder(boolean verbose, boolean sorted) {
    this(verbose);
    setSortNames(sorted);
  }
  protected boolean verbose;
  /**
   * Get the verbose mode state.
   * 
   * @return verbosity
   */
  public boolean getVerbose() {
    return verbose;
  }
  /**
   * set the verbose mode state
   * 
   * @param f -
   *          verbosity
   */
  public void setVerbose(boolean f) {
    verbose = f;
  }
  protected boolean sortNames;
  /**
   * @return Returns the sortNames.
   */
  public boolean getSortNames() {
    return sortNames;
  }
  /**
   * @param sortNames
   *          The sortNames to set.
   */
  public void setSortNames(boolean sortNames) {
    this.sortNames = sortNames;
  }
  /**
   * Explode source JAR and/or ZIP files into a target directory
   * 
   * @param zipNames
   *          names of source files
   * @param jarNames
   *          names of source files
   * @param destDir
   *          target directory name (should already exist)
   * @exception IOException
   *              error creating a target file
   */
  public void process(String[] zipNames, String[] jarNames, String destDir) throws IOException {
    processZips(zipNames, destDir);
    processJars(jarNames, destDir);
  }
  /**
   * Explode source JAR files into a target directory
   * 
   * @param jarNames
   *          names of source files
   * @param destDir
   *          target directory name (should already exist)
   * @exception IOException
   *              error creating a target file
   */
  public void processJars(String[] jarNames, String destDir) throws IOException {
    for (int i = 0; i < jarNames.length; i++) {
      processFile(jarNames[i], destDir);
    }
  }
  /**
   * Explode source ZIP files into a target directory
   * 
   * @param zipNames
   *          names of source files
   * @param destDir
   *          target directory name (should already exist)
   * @exception IOException
   *              error creating a target file
   */
  public void processZips(String[] zipNames, String destDir) throws IOException {
    for (int i = 0; i < zipNames.length; i++) {
      processFile(zipNames[i], destDir);
    }
  }
  /**
   * Explode source ZIP or JAR file into a target directory
   * 
   * @param zipName
   *          names of source file
   * @param destDir
   *          target directory name (should already exist)
   * @exception IOException
   *              error creating a target file
   */
  public void processFile(String zipName, String destDir) throws IOException {
    String source = new File(zipName).getCanonicalPath();
    String dest = new File(destDir).getCanonicalPath();
    ZipFile f = null;
    try {
      f = new ZipFile(source);
      Map fEntries = getEntries(f);
      String[] names = (String[]) fEntries.keySet().toArray(new String[] {});
      if (sortNames) {
        Arrays.sort(names);
      }
      // copy all files
      for (int i = 0; i < names.length; i++) {
        String name = names[i];
        ZipEntry e = (ZipEntry) fEntries.get(name);
        copyFileEntry(dest, f, e);
      }
    } catch (IOException ioe) {
      String msg = ioe.getMessage();
      if (msg.indexOf(zipName) < 0) {
        msg += " - " + zipName;
      }
      throw new IOException(msg);
    } finally {
      if (f != null) {
        try {
          f.close();
        } catch (IOException ioe) {
        }
      }
    }
  }
  /** Get all the entries in a ZIP file. */
  protected Map getEntries(ZipFile zf) {
    Enumeration e = zf.entries();
    Map m = new HashMap();
    while (e.hasMoreElements()) {
      ZipEntry ze = (ZipEntry) e.nextElement();
      m.put(ze.getName(), ze);
    }
    return m;
  }
  /**
   * copy a single entry from the archive
   * 
   * @param destDir
   * @param zf
   * @param ze
   * @throws IOException
   */
  public void copyFileEntry(String destDir, ZipFile zf, ZipEntry ze) throws IOException {
    DataInputStream dis = new DataInputStream(new BufferedInputStream(zf.getInputStream(ze)));
    try {
      copyFileEntry(destDir, ze.isDirectory(), ze.getName(), dis);
    } finally {
      try {
        dis.close();
      } catch (IOException ioe) {
      }
    }
  }
  protected void copyFileEntry(String destDir, boolean destIsDir, String destFile,
      DataInputStream dis) throws IOException {
    byte[] bytes = readAllBytes(dis);
    File file = new File(destFile);
    String parent = file.getParent();
    if (parent != null && parent.length() > 0) {
      File dir = new File(destDir, parent);
      if (dir != null) {
        dir.mkdirs();
      }
    }
    File outFile = new File(destDir, destFile);
    if (destIsDir) {
      outFile.mkdir();
    } else {
      FileOutputStream fos = new FileOutputStream(outFile);
      try {
        fos.write(bytes, 0, bytes.length);
      } finally {
        try {
          fos.close();
        } catch (IOException ioe) {
        }
      }
    }
  }
  // *** below may be slow for large files ***
  /** Read all the bytes in a ZIPed file */
  protected byte[] readAllBytes(DataInputStream is) throws IOException {
    byte[] bytes = new byte[0];
    for (int len = is.available(); len > 0; len = is.available()) {
      byte[] xbytes = new byte[len];
      int count = is.read(xbytes);
      if (count > 0) {
        byte[] nbytes = new byte[bytes.length + count];
        System.arraycopy(bytes, 0, nbytes, 0, bytes.length);
        System.arraycopy(xbytes, 0, nbytes, bytes.length, count);
        bytes = nbytes;
      } else if (count < 0) {
        // accommodate apparent bug in IBM JVM where
        // available() always returns positive value on some files
        break;
      }
    }
    return bytes;
  }
  protected void print(String s) {
    System.out.print(s);
  }
  /** Print command help text. */
  protected static void printHelp() {
    System.out.println();
    System.out.println("Usage: java " + ZipExploder.class.getName()
        + " (-jar jarFilename... | -zip zipFilename...)... -dir destDir {-verbose}");
    System.out.println("Where:");
    System.out.println("  jarFilename path to source jar, may repeat");
    System.out.println("  zipFilename path to source zip, may repeat");
    System.out.println("  destDir    path to target directory; should exist");
    System.out.println("Note: one -jar or -zip is required; switch case or order is not important");
  }
  protected static void reportError(String msg) {
    System.err.println(msg);
    // printHelp();
    System.exit(1);
  }
  /**
   * Main command line entry point.
   * 
   * @param args
   */
  public static void main(final String[] args) {
    if (args.length == 0) {
      printHelp();
      System.exit(0);
    }
    List zipNames = new ArrayList();
    List jarNames = new ArrayList();
    String destDir = null;
    boolean jarActive = false, zipActive = false, destDirActive = false;
    boolean verbose = false;
    // process arguments
    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.charAt(0) == "-") { // switch
        arg = arg.substring(1);
        if (arg.equalsIgnoreCase("jar")) {
          jarActive = true;
          zipActive = false;
          destDirActive = false;
        } else if (arg.equalsIgnoreCase("zip")) {
          zipActive = true;
          jarActive = false;
          destDirActive = false;
        } else if (arg.equalsIgnoreCase("dir")) {
          jarActive = false;
          zipActive = false;
          destDirActive = true;
        } else if (arg.equalsIgnoreCase("verbose")) {
          verbose = true;
        } else {
          reportError("Invalid switch - " + arg);
        }
      } else {
        if (jarActive) {
          jarNames.add(arg);
        } else if (zipActive) {
          zipNames.add(arg);
        } else if (destDirActive) {
          if (destDir != null) {
            reportError("duplicate argument - " + "-destDir");
          }
          destDir = arg;
        } else {
          reportError("Too many parameters - " + arg);
        }
      }
    }
    if (destDir == null || (zipNames.size() + jarNames.size()) == 0) {
      reportError("Missing parameters");
    }
    if (verbose) {
      System.out.println("Effective command: " + ZipExploder.class.getName() + " "
          + (jarNames.size() > 0 ? "-jars " + jarNames + " " : "")
          + (zipNames.size() > 0 ? "-zips " + zipNames + " " : "") + "-dir " + destDir);
    }
    try {
      ZipExploder ze = new ZipExploder(verbose);
      ze.process((String[]) zipNames.toArray(new String[zipNames.size()]), (String[]) jarNames
          .toArray(new String[jarNames.size()]), destDir);
    } catch (IOException ioe) {
      System.err.println("Exception - " + ioe.getMessage());
      ioe.printStackTrace(); // *** debug ***
      System.exit(2);
    }
  }
}





Create a Jar archive containing the src file/directory

 
    
/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
/** A utility class for dealing with Jar files.
@author Scott.Stark@jboss.org
@version $Revision: 2787 $
*/
public final class JarUtils
{
   /**
    * Hide the constructor
    */
   private JarUtils()
   {
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, new File[] { src }, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File src) throws IOException
   {
      jar(out, new File[] { src }, null, null, null);
   }
 
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src) throws IOException
   {
      jar(out, src, null, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, filter, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter)
      throws IOException
   {
      jar(out, src, filter, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @param prefix The name of an arbitrary directory that will precede all
    *        entries in the jar archive.  If null, then no prefix will be
    *        used.
    * @param man The manifest to use for the Jar archive.  If null, then no
    *        manifest will be included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter,
      String prefix, Manifest man) throws IOException
   {
      
      for (int i = 0; i < src.length; i++)
      {
         if (!src[i].exists())
         {
            throw new FileNotFoundException(src.toString());
         }
      }
      
      JarOutputStream jout;
      if (man == null)
      {
         jout = new JarOutputStream(out);
      }
      else
      {
         jout = new JarOutputStream(out, man);
      }
      if (prefix != null && prefix.length() > 0 && !prefix.equals("/"))
      {
         // strip leading "/"
         if (prefix.charAt(0) == "/")
         {
            prefix = prefix.substring(1);
         }
         // ensure trailing "/"
         if (prefix.charAt(prefix.length() - 1) != "/")
         {
            prefix = prefix + "/";
         }
      } 
      else
      {
         prefix = "";
      }
      JarInfo info = new JarInfo(jout, filter);
      for (int i = 0; i < src.length; i++)
      {
         jar(src[i], prefix, info);
      }
      jout.close();
   }
   
   /**
    * This simple convenience class is used by the jar method to reduce the
    * number of arguments needed.  It holds all non-changing attributes
    * needed for the recursive jar method.
    */
   private static class JarInfo
   {
      public JarOutputStream out;
      public FileFilter filter;
      public byte[] buffer;
      
      public JarInfo(JarOutputStream out, FileFilter filter)
      {
         this.out = out;
         this.filter = filter;
         buffer = new byte[1024];
      }
   }
   
   /**
    * This recursive method writes all matching files and directories to
    * the jar output stream.
    */
   private static void jar(File src, String prefix, JarInfo info)
      throws IOException
   {
      
      JarOutputStream jout = info.out;
      if (src.isDirectory())
      {
         // create / init the zip entry
         prefix = prefix + src.getName() + "/";
         ZipEntry entry = new ZipEntry(prefix);
         entry.setTime(src.lastModified());
         entry.setMethod(JarOutputStream.STORED);
         entry.setSize(0L);
         entry.setCrc(0L);
         jout.putNextEntry(entry);
         jout.closeEntry();
         
         // process the sub-directories
         File[] files = src.listFiles(info.filter);
         for (int i = 0; i < files.length; i++)
         {
            jar(files[i], prefix, info);
         }
      } 
      else if (src.isFile())
      {
         // get the required info objects
         byte[] buffer = info.buffer;
         
         // create / init the zip entry
         ZipEntry entry = new ZipEntry(prefix + src.getName());
         entry.setTime(src.lastModified());
         jout.putNextEntry(entry);
         
         // dump the file
         FileInputStream in = new FileInputStream(src);
         int len;
         while ((len = in.read(buffer, 0, buffer.length)) != -1)
         {
            jout.write(buffer, 0, len);
         }
         in.close();
         jout.closeEntry();
      }
   }
   
   public static void unjar(InputStream in, File dest) throws IOException
   {
      if (!dest.exists())
      {
         dest.mkdirs();
      }
      if (!dest.isDirectory())
      {
         throw new IOException("Destination must be a directory.");
      }
      JarInputStream jin = new JarInputStream(in);
      byte[] buffer = new byte[1024];
      
      ZipEntry entry = jin.getNextEntry();
      while (entry != null)
      {
         String fileName = entry.getName();
         if (fileName.charAt(fileName.length() - 1) == "/")
         {
            fileName = fileName.substring(0, fileName.length() - 1);
         }
         if (fileName.charAt(0) == "/")
         {
            fileName = fileName.substring(1);
         }
         if (File.separatorChar != "/")
         {
            fileName = fileName.replace("/", File.separatorChar);
         }
         File file = new File(dest, fileName);
         if (entry.isDirectory())
         {
            // make sure the directory exists
            file.mkdirs();
            jin.closeEntry();
         } 
         else
         {
            // make sure the directory exists
            File parent = file.getParentFile();
            if (parent != null && !parent.exists())
            {
               parent.mkdirs();
            }
            
            // dump the file
            OutputStream out = new FileOutputStream(file);
            int len = 0;
            while ((len = jin.read(buffer, 0, buffer.length)) != -1)
            {
               out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
            jin.closeEntry();
            file.setLastModified(entry.getTime());
         }
         entry = jin.getNextEntry();
      }
      /* Explicity write out the META-INF/MANIFEST.MF so that any headers such
      as the Class-Path are see for the unpackaged jar
      */
      Manifest mf = jin.getManifest();
      if (mf != null)
      {
         File file = new File(dest, "META-INF/MANIFEST.MF");
         File parent = file.getParentFile();
         if( parent.exists() == false )
         {
            parent.mkdirs();
         }
         OutputStream out = new FileOutputStream(file);
         mf.write(out);
         out.flush();
         out.close();
      }
      jin.close();
   }
   /** Given a URL check if its a jar url(jar:<url>!/archive) and if it is,
    extract the archive entry into the given dest directory and return a file
    URL to its location. If jarURL is not a jar url then it is simply returned
    as the URL for the jar.
    @param jarURL the URL to validate and extract the referenced entry if its
      a jar protocol URL
    @param dest the directory into which the nested jar will be extracted.
    @return the file: URL for the jar referenced by the jarURL parameter.
    * @throws IOException 
    */
   public static URL extractNestedJar(URL jarURL, File dest)
      throws IOException
   {
      // This may not be a jar URL so validate the protocol 
      if( jarURL.getProtocol().equals("jar") == false )
         return jarURL;
      String destPath = dest.getAbsolutePath();
      URLConnection urlConn = jarURL.openConnection();
      JarURLConnection jarConn = (JarURLConnection) urlConn;
      // Extract the archive to dest/jarName-contents/archive
      String parentArchiveName = jarConn.getJarFile().getName();
      // Find the longest common prefix between destPath and parentArchiveName
      int length = Math.min(destPath.length(), parentArchiveName.length());
      int n = 0;
      while( n < length )
      {
         char a = destPath.charAt(n);
         char b = parentArchiveName.charAt(n);
         if( a != b )
            break;
         n ++;
      }
      // Remove any common prefix from parentArchiveName
      parentArchiveName = parentArchiveName.substring(n);
      File archiveDir = new File(dest, parentArchiveName+"-contents");
      if( archiveDir.exists() == false && archiveDir.mkdirs() == false )
         throw new IOException("Failed to create contents directory for archive, path="+archiveDir.getAbsolutePath());
      String archiveName = jarConn.getEntryName();
      File archiveFile = new File(archiveDir, archiveName);
      File archiveParentDir = archiveFile.getParentFile();
      if( archiveParentDir.exists() == false && archiveParentDir.mkdirs() == false )
         throw new IOException("Failed to create parent directory for archive, path="+archiveParentDir.getAbsolutePath());
      InputStream archiveIS = jarConn.getInputStream();
      FileOutputStream fos = new FileOutputStream(archiveFile);
      BufferedOutputStream bos = new BufferedOutputStream(fos);
      byte[] buffer = new byte[4096];
      int read;
      while( (read = archiveIS.read(buffer)) > 0 )
      {
         bos.write(buffer, 0, read);
      }
      archiveIS.close();
      bos.close();
      // Return the file url to the extracted jar
      return archiveFile.toURL();
   }

   public static void main(String[] args) throws Exception
   {
      if (args.length == 0)
      {
         System.out.println("usage: <x or c> <jar-archive> <files...>");
         System.exit(0);
      }
      if (args[0].equals("x"))
      {
         BufferedInputStream in = new BufferedInputStream(new FileInputStream(args[1]));
         File dest = new File(args[2]);
         unjar(in, dest);
      }
      else if (args[0].equals("c"))
      {
         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(args[1]));
         File[] src = new File[args.length - 2];
         for (int i = 0; i < src.length; i++)
         {
            src[i] = new File(args[2 + i]);
         }
         jar(out, src);
      }
      else
      {
         System.out.println("Need x or c as first argument");
      }
   }
}





Create a URL that refers to a jar file in the file system

    
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
  }
}





Create a URL that refers to an entry in the jar file

    
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/com/mycompany/MyClass.class");
  }
}





Create Jar file

    
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class CreateJarFile {
  public static int BUFFER_SIZE = 10240;
  protected void createJarArchive(File archiveFile, File[] tobeJared) {
    try {
      byte buffer[] = new byte[BUFFER_SIZE];
      // Open archive file
      FileOutputStream stream = new FileOutputStream(archiveFile);
      JarOutputStream out = new JarOutputStream(stream, new Manifest());
      for (int i = 0; i < tobeJared.length; i++) {
        if (tobeJared[i] == null || !tobeJared[i].exists()
            || tobeJared[i].isDirectory())
          continue; // Just in case...
        System.out.println("Adding " + tobeJared[i].getName());
        // Add archive entry
        JarEntry jarAdd = new JarEntry(tobeJared[i].getName());
        jarAdd.setTime(tobeJared[i].lastModified());
        out.putNextEntry(jarAdd);
        // Write file to archive
        FileInputStream in = new FileInputStream(tobeJared[i]);
        while (true) {
          int nRead = in.read(buffer, 0, buffer.length);
          if (nRead <= 0)
            break;
          out.write(buffer, 0, nRead);
        }
        in.close();
      }
      out.close();
      stream.close();
      System.out.println("Adding completed OK");
    } catch (Exception ex) {
      ex.printStackTrace();
      System.out.println("Error: " + ex.getMessage());
    }
  }
}





Creating a JAR File

    
// Create the jar file
jar cf myjar.jar MyClass.class





Determine whether a file is a JAR File.

 
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipFile;
public class Main {
  /**
   * Determine whether a file is a JAR File.
   */
  public static boolean isJarFile(File file) throws IOException {
    if (!isZipFile(file)) {
      return false;
    }
    ZipFile zip = new ZipFile(file);
    boolean manifest = zip.getEntry("META-INF/MANIFEST.MF") != null;
    zip.close();
    return manifest;
  }
  /**
   * Determine whether a file is a ZIP File.
   */
  public static boolean isZipFile(File file) throws IOException {
      if(file.isDirectory()) {
          return false;
      }
      if(!file.canRead()) {
          throw new IOException("Cannot read file "+file.getAbsolutePath());
      }
      if(file.length() < 4) {
          return false;
      }
      DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
      int test = in.readInt();
      in.close();
      return test == 0x504b0304;
  }
}





Get resource from Jar file

  
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public final class JarResource {
  public List<String> getJarContents(URL jarLocation) throws IOException {
    return getJarContents(jarLocation.openStream());
  }
  public List<String> getJarContents(InputStream is) throws IOException {
    return load(is);
  }
  public List<String> getJarContents(String jarLocation) throws IOException {
    return getJarContents(new File(jarLocation));
  }
  public List<String> getJarContents(File jarFile) throws IOException {
    return load(jarFile);
  }
  private List<String> load(File jarFile) throws IOException {
    List<String> jarContents = new ArrayList<String>();
    try {
      ZipFile zf = new ZipFile(jarFile);
      for (Enumeration e = zf.entries(); e.hasMoreElements();) {
        ZipEntry ze = (ZipEntry) e.nextElement();
        if (ze.isDirectory()) {
          continue;
        }
        jarContents.add(ze.getName());
      }
    } catch (NullPointerException e) {
      System.out.println("done.");
    } catch (ZipException ze) {
      ze.printStackTrace();
    }
    return jarContents;
  }
  private List<String> load(InputStream is) throws IOException {
    List<String> jarContents = new ArrayList<String>();
    try {
      ZipInputStream zis = new ZipInputStream(is);
      ZipEntry ze = zis.getNextEntry();
      while (ze != null) {
        if (ze.isDirectory()) {
          continue;
        }
        jarContents.add(ze.getName());
        ze = zis.getNextEntry();
      }
    } catch (NullPointerException e) {
      System.out.println("done.");
    }
    return jarContents;
  }
}





Get the entry name; it should be the same as specified on URL

    
import java.net.JarURLConnection;
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
    JarURLConnection conn = (JarURLConnection) url.openConnection();
    String entryName = conn.getEntryName();
  }
}





Get the jar entry

    
import java.net.JarURLConnection;
import java.net.URL;
import java.util.jar.JarEntry;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
    JarURLConnection conn = (JarURLConnection) url.openConnection();
    JarEntry jarEntry = conn.getJarEntry();
  }
}





Get the jar file

    
import java.net.JarURLConnection;
import java.net.URL;
import java.util.jar.JarFile;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
    JarURLConnection conn = (JarURLConnection) url.openConnection();
    conn = (JarURLConnection) url.openConnection();
    JarFile jarfile = conn.getJarFile();
  }
}





Get the jar file from a URL

    
import java.net.JarURLConnection;
import java.net.URL;
import java.util.jar.JarFile;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
    JarURLConnection conn = (JarURLConnection) url.openConnection();
    JarFile jarfile = conn.getJarFile();
  }
}





Getting a Jar File Using a URL

    
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    // Create a URL that refers to a jar file on the net
    URL url = new URL("jar:http://hostname/my.jar!/");
  }
}





Helper Class to manipulate Java Archive File

   
/* -------------------------------------------------------------------------*
 * PKUAS: Peking University Application Server
 * Copyright (C) 2006 Peking University
 *
 * This software is free; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * either version 2.1 or any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 * ------------------------------------------------------------------------*/

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
 * This is the Helper Class to manipulate Java Archive File
 * @author Lin Liang
 */
public class JarMaker {
    public JarMaker() {
    }
    public static boolean pack(String jarPath, String jarFileName) {
        try {
            String t_jarPathName = jarPath.replace("\\", File.separatorChar);
            String t_jarFileName = jarFileName.replace("\\", File.separatorChar);
            RealPackUtilityJar(t_jarPathName, t_jarFileName);
            return true;
        } catch (Exception ex) {
            return false;
        }
    }
    public static boolean utilityPack(String p_utilityFileName, String jarName) {
        try {
            // begin to pack the utility jar file.
            String t_utilityfilename = p_utilityFileName.replace("\\", File.separatorChar);
            String t_jarfilename = jarName.replace("\\", File.separatorChar) + ".jar";
            // File utilityFile = new File(p_utilityFileName);
            RealPackUtilityJar(t_utilityfilename, t_jarfilename);
            // delete the utility directory!
        } catch (Exception ex) {
            return false;
        }
        return true;
    }
    public static void RealPackUtilityJar(String s_src, String s_dest) throws IOException {
        URL _src, _dest;
        File f_src = new File(s_src);
        if (!f_src.isDirectory())
            throw new IOException(s_src + " is not a directory");
        _src = f_src.toURL();
        _dest = new File(s_dest).toURL();
        int path_l = s_dest.lastIndexOf("/");
        if (path_l > 0) {
            File dir = new File(s_dest.substring(0, path_l));
            if (!dir.exists())
                dir.mkdirs();
        }
        JarOutputStream jout = new JarOutputStream(new FileOutputStream(_dest.getFile()));
        // put all into the jar...
        add(jout, new File(_src.getFile()), "");
        jout.close();
    }
    /**
     * used by downloadAndPack
     * @param _jout
     * @param _dir
     * @param _prefix
     * @throws IOException
     */
    public static void add(JarOutputStream _jout, File _dir, String _prefix) throws IOException {
        File[] content = _dir.listFiles();
        if (_dir.isDirectory()) {
            for (int i = 0, l = content.length; i < l; ++i) {
                if (content[i].isDirectory()) {
                    _jout.putNextEntry(new ZipEntry(_prefix + (_prefix.equals("") ? "" : "/") + content[i].getName() + "/"));
                    add(_jout, content[i], _prefix + (_prefix.equals("") ? "" : "/") + content[i].getName());
                } else {
                    _jout.putNextEntry(new ZipEntry(_prefix + (_prefix.equals("") ? "" : "/") + content[i].getName()));
                    FileInputStream in = new FileInputStream(content[i]);
                    write(in, _jout);
                    in.close();
                }
            }
        } else {
            _jout.putNextEntry(new ZipEntry(_prefix + (_prefix.equals("") ? "" : "/") + _dir.getName()));
            FileInputStream in = new FileInputStream(_dir);
            write(in, _jout);
            in.close();
        }
    }
    /**
     * writes the content of the InputStream into the OutputStream
     * @param _in
     * @param _out
     * @throws IOException
     */
    private static synchronized void write(InputStream _in, OutputStream _out) throws IOException {
        byte[] buffer = new byte[1024 * 512];
        int read;
        while (true) {
            read = _in.read(buffer);
            if (read == -1)
                break;
            _out.write(buffer, 0, read);
        }
        _out.flush();
    }
    /**
     * Deletes all files and subdirectories under dir.
     * @param dir
     * @return true if all deletions were successful.If a deletion fails, the
     *         method stops attempting to delete and returns false.
     */
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // The directory is now empty so delete it
        return dir.delete();
    }
    /**
     * @param f_name : source zip file
     * @param dir_name : target dir file
     */
    public static void unpackJar(File f_name, File dir_name) throws IOException {
        unpackJar(f_name.getCanonicalPath(), dir_name.getCanonicalPath());
    }
    /**
     * @param f_name : source zip file path name
     * @param dir_name : target dir file path
     */
    public static void unpackJar(String f_name, String dir_name) throws IOException {
        BufferedInputStream bism = new BufferedInputStream(new FileInputStream(f_name));
        ZipInputStream zism = new ZipInputStream(bism);
        for (ZipEntry z = zism.getNextEntry(); z != null; z = zism.getNextEntry()) {
            File f = new File(dir_name, z.getName());
            if (z.isDirectory()) {
                f.mkdirs();
            } else {
                f.getParentFile().mkdirs();
                BufferedOutputStream bosm = new BufferedOutputStream(new FileOutputStream(f));
                int i;
                byte[] buffer = new byte[1024 * 512];
                try {
                    while ((i = zism.read(buffer, 0, buffer.length)) != -1)
                        bosm.write(buffer, 0, i);
                } catch (IOException ie) {
                    throw ie;
                }
                bosm.close();
            }
        }
        zism.close();
        bism.close();
    }
    /**
     * Unpack the jar file to a directory, till teaf files
     * @param file
     * @param file1
     * @throws IOException
     */
    public static void unpackAppJar(File file, File file1) throws IOException {
        unpackAppJar(file.getCanonicalPath(), file1.getCanonicalPath());
    }
    /**
     * Unpack the jar file to a directory, till teaf files
     * @param file The source file name
     * @param file1 The target directory
     * @author wangxp
     * @version 2003/11/07
     */
    public static void unpackAppJar(String file, String file1) throws IOException {
        // m_log.debug("unpackAppJar begin. file="+file+"|||file1="+file1);
        BufferedInputStream bufferedinputstream = new BufferedInputStream(new FileInputStream(file));
        ZipInputStream zipinputstream = new ZipInputStream(bufferedinputstream);
        byte abyte0[] = new byte[1024];
        for (ZipEntry zipentry = zipinputstream.getNextEntry(); zipentry != null; zipentry = zipinputstream.getNextEntry()) {
            File file2 = new File(file1, zipentry.getName());
            if (zipentry.isDirectory()) {
                if (!file2.exists() && !file2.mkdirs())
                    throw new IOException("Could not make directory " + file2.getPath());
            } else {
                File file3 = file2.getParentFile();
                if (file3 != null && !file3.exists() && !file3.mkdirs())
                    throw new IOException("Could not make directory " + file3.getPath());
                BufferedOutputStream bufferedoutputstream = new BufferedOutputStream(new FileOutputStream(file2));
                int i;
                try {
                    while ((i = zipinputstream.read(abyte0, 0, abyte0.length)) != -1)
                        bufferedoutputstream.write(abyte0, 0, i);
                } catch (IOException ie) {
                    ie.printStackTrace();
                    // m_logger.error(ie);
                    throw ie;
                }
                bufferedoutputstream.close();
            }
        }
        zipinputstream.close();
        bufferedinputstream.close();
        // m_log.debug("unpackAppJar end.");
    }
    /**
     * Combine several jar files and some given files into one jar file.
     * @param outJar The output jar file"s filename.
     * @param inJarsList The jar files to be combined
     * @param filter A filter that exclude some entries of input jars. User
     *        should implement the EntryFilter interface.
     * @param inFileList The files to be added into the jar file.
     * @param prefixs The prefixs of files to be added into the jar file.
     *        inFileList and prefixs should be paired.
     * @throws FileNotFoundException
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public static void combineJars(String outJar, String[] inJarsList, EntryFilter filter, String[] inFileList, String[] prefixs)
            throws FileNotFoundException, IOException {
        JarOutputStream jout = new JarOutputStream(new FileOutputStream(outJar));
        ArrayList entryList = new ArrayList();
        for (int i = 0; i < inJarsList.length; i++) {
            BufferedInputStream bufferedinputstream = new BufferedInputStream(new FileInputStream(inJarsList[i]));
            ZipInputStream zipinputstream = new ZipInputStream(bufferedinputstream);
            byte abyte0[] = new byte[1024 * 4];
            for (ZipEntry zipentry = zipinputstream.getNextEntry(); zipentry != null; zipentry = zipinputstream.getNextEntry()) {
                if (filter.accept(zipentry)) {
                    if (!entryList.contains(zipentry.getName())) {
                        jout.putNextEntry(zipentry);
                        if (!zipentry.isDirectory()) {
                            int j;
                            try {
                                while ((j = zipinputstream.read(abyte0, 0, abyte0.length)) != -1)
                                    jout.write(abyte0, 0, j);
                            } catch (IOException ie) {
                                throw ie;
                            }
                        }
                        entryList.add(zipentry.getName());
                    }
                }
            }
            zipinputstream.close();
            bufferedinputstream.close();
        }
        for (int i = 0; i < inFileList.length; i++) {
            add(jout, new File(inFileList[i]), prefixs[i]);
        }
        jout.close();
    }
    /**
     * Test
     * @param args
     * @throws Exception
     */
    public static void main(String args[]) throws Exception {
        String[] in = new String[2];
        in[1] = "E:\\pkuas03\\pkuas_51\\repository\\deployed\\ecperf.ear\\corp.jar";
        in[0] = "E:\\pkuas03\\pkuas_51\\repository\\deployed\\ecperf.ear\\orders.jar";
        String[] fs = new String[1];
        fs[0] = "E:\\pkuas03\\pkuas_51\\repository\\deployed\\ecperf.ear\\META-INF\\application.xml";
        String[] pres = new String[1];
        pres[0] = "META-INF";
        combineJars("e:\\111.jar", in, new EntryFilter() {
            public boolean accept(ZipEntry entry) {
                if (entry.getName().endsWith("ejb-jar.xml"))
                    return false;
                return true;
            }
        }, fs, pres);
    }
    interface EntryFilter {
        public boolean accept(ZipEntry entry);
    }
}





InstallJars - a utility to download and install files, Jars and Zips.

  
/*******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * IBM Corporation - initial API and implementation                                       
 *******************************************************************************/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/*******************************************************************************
 * * InstallJars - a utility to download and install files, Jars and Zips. * *
 * 
 * @author Barry Feigenbaum, Ph.D. *
 ******************************************************************************/
public class InstallJars {
  public static final int BLOCK_SIZE = 512;
  public static final int BLOCK_COUNT = 20;
  // *** must be a multiple of BLOCK_SIZE ***
  public static int bufferSize = 128 * (2 * BLOCK_SIZE);
  // *** need to NLS enable all user messages ***
  /**
   * Constructor. Expand, run and verbose output requested.
   */
  public InstallJars() {
    this(true, true, true, "InstallJars.properties", "cmd /c java");
  }
  /**
   * Contstructor.
   * 
   * @param expand
   *          <code>true</code> if the archive is t be expanded in the target
   * @param verbose
   *          <code>true</code> if messages are to be generated
   * @param run
   *          <code>true</code> if file is to be executed
   * @param propName
   *          properties file with items to install
   * @param javaParams
   *          java parameters
   */
  public InstallJars(boolean expand, boolean verbose, boolean run, String propName,
      String javaParams) {
    setExpand(expand);
    setVerbose(verbose);
    setRunMode(run);
    setPropFilename(propName);
    setJavaParams(javaParams);
  }
  protected boolean verbose;
  /**
   * Get the verbose mode state.
   * 
   * @return is in verbose mode
   */
  public boolean getVerbose() {
    return verbose;
  }
  /**
   * Set the verbose mode state.
   * 
   * @param f
   *          value
   */
  public void setVerbose(boolean f) {
    verbose = f;
  }
  protected boolean run;
  /**
   * Get the run mode state.
   * 
   * @return is in run mode
   */
  public boolean getRunMode() {
    return run;
  }
  /**
   * Set the run mode state.
   * 
   * @param f
   *          value
   */
  public void setRunMode(boolean f) {
    run = f;
  }
  protected boolean expand;
  /**
   * Get the expand mode state.
   * 
   * @return is expanded
   */
  public boolean getExpand() {
    return expand;
  }
  /**
   * Set the expand mode state.
   * 
   * @param f
   *          value
   */
  public void setExpand(boolean f) {
    expand = f;
  }
  protected String propFilename;
  /**
   * Get the propFilename mode state.
   * 
   * @return prooperty file name
   */
  public String getPropFilename() {
    return propFilename;
  }
  /**
   * Set the propFilename mode state.
   * 
   * @param name
   */
  public void setPropFilename(String name) {
    propFilename = name;
  }
  protected String javaParams = "cmd /c java";
  /**
   * Get the JavaParams mode state.
   * 
   * @return java parameters
   */
  public String getJavaParams() {
    return javaParams;
  }
  /**
   * Set the JavaParams mode state.
   * 
   * @param p
   *          value
   */
  public void setJavaParams(String p) {
    javaParams = p;
  }
  protected void print(String s) {
    if (verbose) {
      System.out.print(s);
    }
  }
  protected void println(String s) {
    if (verbose) {
      System.out.println(s);
    }
  }
  protected void println() {
    println("");
  }
  /**
   * Install based on a properties file<br>
   * 
   * @return recommended classpath
   * @exception IOException
   *              Thrown if a JAR file access error occurs
   */
  public String install() throws IOException {
    StringBuffer classpath = new StringBuffer();
    Properties prop = new Properties();
    prop.load(new BufferedInputStream(new FileInputStream(propFilename)));
    for (Iterator i = prop.keySet().iterator(); i.hasNext();) {
      String key = (String) i.next();
      String value = prop.getProperty(key);
      String xurl = null;
      String xdir = null;
      String xcp = null;
      boolean xexpand = expand, xrun = run;
      if (value != null) {
        value = value.trim();
        if (value.length() > 0) {
          String delim = value.substring(0, 1);
          StringTokenizer st = new StringTokenizer(value.substring(1), delim);
          xurl = st.nextToken();
          xdir = (st.hasMoreTokens() ? st.nextToken() : ".").trim();
          if (xdir.length() == 0) {
            xdir = ".";
          }
          xcp = (st.hasMoreTokens() ? st.nextToken() : xdir).trim();
          if (xcp.length() == 0) {
            xcp = xdir;
          }
          classpath.append(xcp);
          classpath.append(";");
          while (st.hasMoreTokens()) {
            String xoption = st.nextToken().trim();
            if (xoption.equalsIgnoreCase("expand")) {
              xexpand = true;
            } else if (xoption.equalsIgnoreCase("noexpand")) {
              xexpand = false;
            } else if (xoption.equalsIgnoreCase("run")) {
              xrun = true;
            } else if (xoption.equalsIgnoreCase("norun")) {
              xrun = false;
            } else {
              throw new IllegalArgumentException("invalid install property - " + key + "=" + value);
            }
          }
        }
      }
      if (xurl == null || xurl.length() == 0) {
        throw new IllegalArgumentException("missing install property - " + key + "=" + value);
      }
      System.out.print("\nInstalling " + key);
      if (verbose) {
        System.out.print(" using URL=" + xurl + "; target=" + xdir + "; classpath=" + xcp + "; "
            + (xexpand ? "expand" : "noexpand") + "; " + (xrun ? "run" : "norun"));
      }
      System.out.println("...");
      installFile(xurl, xdir, xexpand, xrun);
    }
    return classpath.toString();
  }
  /**
   * Install a Zip/Jar file.
   * 
   * @param fileUrl
   *          The file/zip/jar file
   * @param targetPath
   *          root of directory or file to install into
   * @param doExpand
   * @param doRun
   * @exception IOException
   *              Thrown if a JAR file access error occurs
   */
  public void installFile(String fileUrl, String targetPath, boolean doExpand, boolean doRun)
      throws IOException {
    String targetFilename = new File(targetPath).getCanonicalPath().replace("\\", "/");
    println("Installing in " + targetFilename);
    URL url = new URL(fileUrl);
    URLConnection conn = url.openConnection();
    // System.out.println("Conn = " + conn);
    String ctype = conn.getContentType();
    println("Content type is " + ctype);
    String extension = getExtension(fileUrl);
    if (extension.equals("class")) {
      installClass(conn, targetFilename, doExpand, doRun);
      // println("Installed class file " + fileUrl + "; please run");
    } else if (extension.equalsIgnoreCase("zip")) {
      installZip(conn, targetFilename, doExpand, doRun);
      // println("Installed ZIP file " + fileUrl + "; ZIP expanded");
    } else if (extension.equalsIgnoreCase("gz")) {
      installGZip(conn, targetFilename, doExpand, doRun);
      // println("Installed GZIP file " + fileUrl + "; ZIP expanded");
    } else if (extension.equalsIgnoreCase("jar")) {
      installJar(conn, targetFilename, doExpand, doRun);
      // System.out.println("Installed JAR file " + fileUrl + "; please add to
      // CLASSPATH");
    } else {
      throw new IllegalArgumentException("Unknown extension - " + extension);
    }
  }
  public void installClass(URLConnection conn, String target, boolean doExpand, boolean doRun)
      throws IOException {
    // doExpand not used on htis type
    print("Installing class file " + target + " from " + conn.getURL().toExternalForm());
    copyStream(conn, target);
    println();
    if (doRun) {
      runTarget(target, false);
    }
  }
  protected void runTarget(String target, boolean isJar) throws IOException {
    // *** add run code ***
    if (isJar) {
      System.out.println("runTarget(" + target + "," + isJar + ") not currently implemented");
    } else {
      try {
        String name = removeExtension(getFile(target));
        String cp = "-cp " + removeFile(target);
        String command = javaParams + " " + cp + " " + name + " >" + name + ".out 2>" + name
            + ".err";
        // String command = javaParams + " " + cp + " " + name;
        System.out.println("Running " + command + "...");
        Process p = Runtime.getRuntime().exec(command);
        int rc = p.waitFor();
        System.out.println("Return code=" + rc);
      } catch (Exception e) {
        System.out.println("Exception - " + e.getMessage());
      }
    }
  }
  public void installJar(URLConnection conn, String target, boolean doExpand, boolean doRun)
      throws IOException {
    if (doExpand) {
      println("Expanding JAR file " + target + " from " + conn.getURL().toExternalForm());
      // *** may need to specialize for JAR format ***
      ZipInputStream zis = new ZipInputStream(new BufferedInputStream(conn.getInputStream(),
          BLOCK_SIZE * BLOCK_COUNT));
      int count = 0;
      prepDirs(target, true);
      try {
        while (zis.available() > 0) {
          ZipEntry ze = zis.getNextEntry();
          copyEntry(target, zis, ze);
          count++;
        }
      } finally {
        try {
          zis.close();
        } catch (IOException ioe) {
        }
      }
      println("Installed " + count + " files/directories");
    } else {
      print("Installing JAR file " + target + " from " + conn.getURL().toExternalForm());
      copyStream(conn, target);
      println();
      if (doRun) {
        runTarget(target, true);
      }
    }
  }
  public void installZip(URLConnection conn, String target, boolean doExpand, boolean doRun)
      throws IOException {
    // doRun not used on htis type
    if (doExpand) {
      String ctype = conn.getContentType();
      if (!ctype.equals("application/zip")) {
        throw new IllegalArgumentException("Unkexpected content type - " + ctype);
      }
      println("Expanding ZIP file to " + target + " from " + conn.getURL().toExternalForm());
      ZipInputStream zis = new ZipInputStream(new BufferedInputStream(conn.getInputStream(),
          BLOCK_SIZE * BLOCK_COUNT));
      int count = 0;
      prepDirs(target, true);
      try {
        for (ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry()) {
          copyEntry(target, zis, ze);
          // zis.closeEntry();
          count++;
        }
      } finally {
        try {
          zis.close();
        } catch (IOException ioe) {
        }
      }
      println("Installed " + count + " files/directories");
    } else {
      print("Installing ZIP file " + target + " from " + conn.getURL().toExternalForm());
      copyStream(conn, target);
      println();
    }
  }
  public void installGZip(URLConnection conn, String target, boolean doExpand, boolean doRun)
      throws IOException {
    // doRun not used on htis type
    if (doExpand) {
      String ctype = conn.getContentType();
      if (!ctype.equals("application/x-tar")) {
        throw new IllegalArgumentException("Unkexpected content type - " + ctype);
      }
      print("Expanding GZIP file to " + target + " from " + conn.getURL().toExternalForm());
      prepDirs(target, false);
      GZIPInputStream zis = new GZIPInputStream(new BufferedInputStream(conn.getInputStream(),
          BLOCK_SIZE * BLOCK_COUNT));
      try {
        // BufferedOutputStream os = new BufferedOutputStream(new
        // FileOutputStream(target), BLOCK_SIZE * BLOCK_COUNT);
        // try {
        // byte[] buf = new byte[bufferSize];
        // for (int size = zis.read(buf, 0, buf.length), count = 0;
        // size >= 0;
        // size = zis.read(buf, 0, buf.length), count++) {
        // //if (count % 4 == 0) print(".");
        // os.write(buf, 0, size);
        // }
        // }
        // finally {
        // try { os.flush(); os.close(); } catch (IOException ioe) {}
        // }
        pumpGZip(target, zis);
      } finally {
        try {
          zis.close();
        } catch (IOException ioe) {
        }
      }
      println();
    } else {
      print("Installing GZIP file " + target + " from " + conn.getURL().toExternalForm());
      copyStream(conn, target);
      println();
    }
  }
  /** Copy a zip entry. */
  protected void copyEntry(String target, ZipInputStream zis, ZipEntry ze) throws IOException {
    String name = ze.getName();
    boolean isDir = false;
    if (name.endsWith("/")) {
      name = name.substring(0, name.length() - 1);
      isDir = true;
    }
    String path = target + File.separator + name;
    path = path.replace("\\", "/");
    String mod = ze.getSize() > 0 ? ("[" + ze.getCompressedSize() + ":" + ze.getSize() + "]") : "";
    print("Expanding " + ze + mod + " to " + path);
    prepDirs(path, isDir);
    if (!isDir) {
      BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(path), BLOCK_SIZE
          * BLOCK_COUNT);
      try {
        byte[] buf = new byte[bufferSize];
        for (int size = zis.read(buf, 0, buf.length), count = 0; size >= 0; size = zis.read(buf, 0,
            buf.length), count++) {
          // if (count % 4 == 0) print(".");
          os.write(buf, 0, size);
        }
      } finally {
        try {
          os.flush();
          os.close();
        } catch (IOException ioe) {
        }
      }
    }
    println();
  }
  public void copyStream(URLConnection conn, String target) throws IOException {
    prepDirs(target, false);
    BufferedInputStream is = new BufferedInputStream(conn.getInputStream(), BLOCK_SIZE
        * BLOCK_COUNT);
    BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(target), BLOCK_SIZE
        * BLOCK_COUNT);
    byte[] buf = new byte[bufferSize];
    for (int size = is.read(buf), count = 0; size >= 0; size = is.read(buf), count++) {
      // if (count % 4 == 0) print(".");
      os.write(buf, 0, size);
    }
    os.flush();
    os.close();
    is.close();
  }
  protected static final int OFFSET_NAME = 0;
  protected static final int OFFSET_MODE = OFFSET_NAME + 100;
  protected static final int OFFSET_UID = OFFSET_MODE + 8;
  protected static final int OFFSET_GID = OFFSET_UID + 8;
  protected static final int OFFSET_SIZE = OFFSET_GID + 8;
  protected static final int OFFSET_MTIME = OFFSET_SIZE + 12;
  protected static final int OFFSET_CHKSUM = OFFSET_MTIME + 12;
  protected static final int OFFSET_TYPE = OFFSET_CHKSUM + 8;
  protected static final int OFFSET_LINKNAME = OFFSET_TYPE + 1;
  protected static final int OFFSET_MAGIC = OFFSET_LINKNAME + 100;
  protected static final int OFFSET_VERSION = OFFSET_MAGIC + 6;
  protected static final int OFFSET_UNAME = OFFSET_VERSION + 2;
  protected static final int OFFSET_GNAME = OFFSET_UNAME + 32;
  protected static final int OFFSET_DEVMAJOR = OFFSET_GNAME + 32;
  protected static final int OFFSET_DEVMINOR = OFFSET_DEVMAJOR + 8;
  protected static final int OFFSET_PREFIX = OFFSET_DEVMINOR + 8;
  protected static final int OFFSET_END = OFFSET_PREFIX + 155;
  protected static final String MAGIC = "USTAR";
  protected void pumpGZip(String target, GZIPInputStream zis) throws IOException {
    String curName = null;
    long curSize = 0, remainingSize = 0;
    char curType = 0;
    int curMajor = 0, curMinor = 0;
    boolean inFile = false;
    BufferedOutputStream curOs = null;
    int instFiles = 0, instDirs = 0;
    byte[] buf = new byte[bufferSize];
    top: while (true) {
      int loaded = loadBytes(buf, zis);
      if (loaded < 0) {
        break;
      }
      // System.out.println("pumpGZip: loaded=" + loaded);
      // process each buffer of data
      for (int index = 0; index < loaded; index += BLOCK_SIZE) {
        // System.out.println("pumpGZip: infile=" + inFile + ", remaining=" +
        // remainingSize);
        if (inFile && remainingSize > 0) { // process body part
          int xsize = Math.min((int) remainingSize, BLOCK_SIZE);
          if (curOs != null) {
            curOs.write(buf, index, xsize);
          }
          remainingSize -= xsize;
        } else { // process header block
          if (inFile) {
            inFile = false;
            if (curOs != null) {
              try {
                curOs.flush();
                curOs.close();
              } catch (IOException ioe) {
              }
              println();
            }
          }
          if (isEmptyBlock(buf, index)) { // check logical end of archive
            break top;
          }
          // System.out.println("pumpGZip: header=" + (new String(buf, 0, index,
          // 512)));
          curName = extractString(buf, index + OFFSET_NAME, 100);
          curType = extractChar(buf, index + OFFSET_TYPE);
          curSize = extractLong(buf, index + OFFSET_SIZE, 12);
          remainingSize = curSize;
          if (remainingSize > Integer.MAX_VALUE) {
            throw new IOException("entry size too large - " + remainingSize);
          }
          String mod = "";
          String magic = extractString(buf, index + OFFSET_MAGIC, 6);
          if (magic.equals(MAGIC)) {
            curName = extractString(buf, index + OFFSET_PREFIX, 155) + curName;
            extractInt(buf, index + OFFSET_VERSION, 2);
            curMajor = extractInt(buf, index + OFFSET_DEVMAJOR, 8);
            curMinor = extractInt(buf, index + OFFSET_DEVMINOR, 8);
            if (curMajor > 0 || curMinor > 0) {
              mod = "[" + curMajor + "." + curMinor + "]";
            }
          }
          // System.out.println("pumpGZip: " +
          // magic + "," +
          // curName + "," +
          // curType + "," +
          // curSize + "," +
          // curVersion + "," +
          // curMajor + "," +
          // curMinor);
          String path = target + File.separator + curName;
          path = path.replace("\\", "/");
          curOs = null;
          if (curType == 0 || curType == "0") { // a file
            print("Copying " + curName + mod + " to " + path);
            prepDirs(path, false);
            curOs = new BufferedOutputStream(new FileOutputStream(path), BLOCK_SIZE * BLOCK_COUNT);
            inFile = true;
            instFiles++;
          } else if (curType == "1" || curType == "2") { // a link
            if (curSize > 0) {
              throw new IOException("link entries cannot have content - " + curSize);
            }
            println("Link ignored - " + curName + mod);
          } else if (curType == "5") { // a directory
            if (path.endsWith("/")) {
              path = path.substring(0, path.length() - 1);
            }
            println("Mkdir " + curName + mod + " to " + path);
            prepDirs(path, true);
            instDirs++;
          } else {
            if (curSize > 0) {
              // throw new IOException("entry type " + curType + " cannot have a
              // content - size=" + curSize);
              inFile = true;
            }
            print("Entry type " + curType + " ignored - " + curName + mod);
          }
        }
      }
    }
    println("Installed " + instFiles + " files and " + instDirs + " directories");
  }
  protected int loadBytes(byte[] buf, GZIPInputStream zis) throws IOException {
    int loaded = -1;
    for (int size = zis.read(buf, 0, buf.length), count = 0; size > 0; size = zis.read(buf, loaded,
        buf.length - loaded), count++) {
      // if (count % 4 == 0) print(".");
      // System.out.println("loadBytes: loaded=" + loaded);
      if (loaded < 0) {
        loaded = 0;
      }
      loaded += size;
    }
    return loaded;
  }
  protected boolean isEmptyBlock(byte[] buf, int index) {
    boolean r = true;
    for (int i = 0; r && i < BLOCK_SIZE; i++) {
      r = buf[index++] == 0;
    }
    // System.out.println("isEmptyBlock: " + r);
    return r;
  }
  protected char extractChar(byte[] buf, int index) throws IOException {
    return (char) buf[index];
  }
  protected int extractInt(byte[] buf, int index, int length) throws IOException {
    return (int) extractLong(buf, index, length);
  }
  protected long extractLong(byte[] buf, int index, int length) throws IOException {
    String xsize = extractString(buf, index, length);
    long v = 0;
    for (int i = 0; i < xsize.length(); i++) {
      char c = xsize.charAt(i);
      if (c != " ") {
        if (c < "0" || c > "7") {
          throw new IOException("non-octal digit found - " + c);
        }
        v = v * 8 + (c - "0");
      }
    }
    return v;
  }
  protected String extractString(byte[] buf, int index, int length) throws IOException {
    StringBuffer sb = new StringBuffer();
    for (int i = 0, xindex = index; i < length; i++, xindex++) {
      int c = buf[xindex];
      if (c == 0) {
        break;
      }
      sb.append((char) c);
    }
    // System.out.println("extractString(" + index + "," + length + "): " +
    // sb.toString());
    return sb.toString();
  }
  protected String getFile(String name) {
    int posn = name.lastIndexOf("/");
    return posn > 0 ? name.substring(posn + 1) : name;
  }
  protected String removeFile(String name) {
    int posn = name.lastIndexOf("/");
    return posn > 0 ? name.substring(0, posn) : name;
  }
  protected String removeExtension(String name) {
    int posn1 = name.lastIndexOf("/");
    int posn2 = name.lastIndexOf(".");
    return (posn2 > 0 && posn2 > posn1) ? name.substring(0, posn2) : name;
  }
  protected String extraceFile(String name) {
    int posn = name.lastIndexOf(File.separator);
    return posn >= 0 ? name.substring(posn + 1) : null;
  }
  protected String getExtension(String name) {
    int posn = name.lastIndexOf(".");
    return posn >= 0 ? name.substring(posn + 1) : "";
  }
  protected void prepDirs(String name) {
    prepDirs(name, expand);
  }
  protected void prepDirs(String name, boolean includeLast) {
    File f = new File(includeLast ? name : removeFile(name));
    // System.out.print("(Making " + f + ")");
    f.mkdirs();
  }
  protected void printUsage() {
    println("Effective command: " + getClass().getName() + " " + propFilename
        + (expand ? " -expand" : " -noexpand") + (run ? " -run" : " -norun") + " -java \""
        + javaParams + "\"" + (verbose ? " -verbose" : " -quiet "));
  }
  /** Print command help text. */
  protected static void printHelp() {
    System.out.println();
    System.out
        .println("Usage: java "
            + InstallJars.class.getName()
            + " {propFilename} {-expand | -noexpand} {-run | -norun} {-quiet | -verbose} {-java <params>}");
    System.out.println("Where:");
    System.out
        .println("  propFilename    path to properties file (default=InstallJars.properties)");
    System.out.println("  -expand         expand any top level JAR/ZIP/GZIP (default)");
    System.out.println("  -noexpand       do not expand any top level JAR/ZIP/GZIP");
    System.out.println("  -run            run class or JAR files (default)");
    System.out.println("  -norun          do not run class or JAR files");
    System.out.println("  -verbose        output progress messages (default)");
    System.out.println("  -quiet          suppress most messages");
    System.out.println("  -java           sets java runtime paramters");
    System.out.println();
    System.out.println("Properties file entry format: name=!url{!target{!classpath{!option}...}}");
    System.out.println("Where:");
    System.out.println("  name      name displayed while installing");
    System.out.println("  url       source of items to download and install");
    System.out.println("  target    root of install directory or file (default=.)");
    System.out
        .println("  classpath class path entry to use for this directrory or file (default=target}");
    System.out.println("  option    one of the following options: expand, noexpand, run, norun");
    System.out.println("            if omitted, the command line default is used");
    System.out.println("! is a delimiter, the first non-whitespace character is used.");
    System.out.println("Options expand and run may not apply to all types of files.");
  }
  /**
   * Main command line entry point.
   * 
   * @param args
   */
  public static void main(final String[] args) {
    if (args.length == 0) {
      printHelp();
      System.exit(0);
    }
    String propName = null;
    boolean expand = true;
    boolean verbose = true;
    boolean run = true;
    String params = "cmd /c java";
    // process arguments
    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.charAt(0) == "-") { // switch
        arg = arg.substring(1);
        if (arg.equalsIgnoreCase("quiet")) {
          verbose = false;
        } else if (arg.equalsIgnoreCase("verbose")) {
          verbose = true;
        } else if (arg.equalsIgnoreCase("expand")) {
          expand = true;
        } else if (arg.equalsIgnoreCase("noexpand")) {
          expand = false;
        } else if (arg.equalsIgnoreCase("run")) {
          run = true;
        } else if (arg.equalsIgnoreCase("norun")) {
          run = false;
        } else if (arg.equalsIgnoreCase("java")) {
          run = false;
          if (i < args.length - 1) {
            params = args[++i];
          }
        } else {
          System.err.println("Invalid switch - " + arg);
          System.exit(1);
        }
      } else {
        if (propName == null) {
          propName = arg;
        } else {
          System.err.println("Too many parameters - " + arg);
          System.exit(1);
        }
      }
    }
    if (propName == null) {
      propName = "InstallJars.properties";
    }
    // do the install
    try {
      InstallJars ij = new InstallJars(expand, verbose, run, propName, params);
      ij.printUsage();
      String cp = ij.install();
      System.out.println("\nRecomended additions to your classpath - " + cp);
    } catch (Exception e) {
      System.err.println("\n" + e.getClass().getName() + ": " + e.getMessage());
      if (verbose) {
        e.printStackTrace(); // *** debug ***
      }
      System.exit(2);
    }
  }
}





JAR Archives: Jar Lister

    
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
public class Main {
  public static void main(String[] args) throws IOException {
    JarFile jf = new JarFile("a.jar");
    Enumeration e = jf.entries();
    while (e.hasMoreElements()) {
      JarEntry je = (JarEntry) e.nextElement();
      System.out.println(je.getName());
      long uncompressedSize = je.getSize();
      long compressedSize = je.getCompressedSize();
      long crc = je.getCrc();
      int method = je.getMethod();
      String comment = je.getComment();
      System.out.println(new Date(je.getTime()));
      System.out.println("from  " + uncompressedSize + " bytes to "+ compressedSize);
      if (method == ZipEntry.STORED) {
        System.out.println("ZipEntry.STORED");
      }
      else if (method == ZipEntry.DEFLATED) {
        System.out.println(ZipEntry.DEFLATED);
      }
      System.out.println("Its CRC is " + crc);
      System.out.println(comment);
      System.out.println(je.isDirectory());
      
      Attributes a = je.getAttributes();
      if (a != null) {
        Object[] nameValuePairs = a.entrySet().toArray();
        for (int j = 0; j < nameValuePairs.length; j++) {
          System.out.println(nameValuePairs[j]);
        }
      }
      System.out.println();
    }
  }
}





JAR Archives: Packer200

    

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.jar.JarFile;
import java.util.jar.Pack200;
public class Main {
  public static void main(String[] args) throws Exception {
    JarFile f = new JarFile("a.jar");
    Pack200.Packer packer = Pack200.newPacker();
    OutputStream out = new FileOutputStream("a.pack");
    packer.pack(f, out);
    out.close();
  }
}





JAR Archives: Unpacker200

    

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.zip.GZIPInputStream;
public class Main {
  public static void main(String[] args) throws Exception {
    String inName = "a.pack.gz";
    String outName = "a.unpacked";
    Pack200.Unpacker unpacker = Pack200.newUnpacker();
    JarOutputStream out = new JarOutputStream(new FileOutputStream(outName));
    InputStream in = new FileInputStream(inName);
    in = new GZIPInputStream(in);
    unpacker.unpack(in, out);
    out.close();
  }
}





Jar builder

   
/*BEGIN_COPYRIGHT_BLOCK
 *
 * Copyright (c) 2001-2008, JavaPLT group at Rice University (drjava@rice.edu)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * 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.
 *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR
 * 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.
 *
 * This software is Open Source Initiative approved Open Source Software.
 * Open Source Initative Approved is a trademark of the Open Source Initiative.
 * 
 * This file is part of DrJava.  Download the current version of this project
 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 * 
 * END_COPYRIGHT_BLOCK*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class JarBuilder {
  private JarOutputStream _output;
  
  /** Creates a file file without a manifest
   *
   * @param file the file to write the jar to
   * @throws IOException thrown if the file cannot be opened for writing
   */
  public JarBuilder(File file) throws IOException {
    _output = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(file)), ManifestWriter.DEFAULT);
  }
  
  /** Creates an empty jar file with the given manifest
   *
   * @param jar      the file to write the jar to
   * @param manifest the file that is the manifest for the archive
   * @throws IOException thrown if either file cannot be opened for reading
   */
  public JarBuilder(File jar, File manifest) throws IOException {
    _output = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jar)), new Manifest(new FileInputStream(manifest)));
  }
  
  /** Creates an empty jar file with the given manifest
   *
   * @param jar      the file to write the jar to
   * @param manifest the manifest file for the jar
   * @see ManifestWriter
   */
  public JarBuilder(File jar, Manifest manifest) {
    try {
      _output = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jar)), manifest);
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  
  /** Takes a parent name and a field name and returns the concatenation of them correctly
   *
   * @param parent The parent directory
   * @param name   The name of the file or directory
   * @return the string concatenation of the parent and the name
   */
  private String makeName(String parent, String name) {
    String sep = "/"; // NOTE: This can be a "/" since it is a path in the jar file itself
    if( parent.equals("") )
      return name;
    if (parent.endsWith(sep))
      return parent + name;
    return parent + sep + name;
  }
  
  /** Adds the file to the given path and name
   *
   * @param file     the file to be added
   * @param parent   the directory to the path in which the file is to be added
   * @param fileName the name of the file in the archive
   */
  public void addFile(File file, String parent, String fileName) throws IOException {
    byte data[] = new byte[2048];
    
    FileInputStream fi = new FileInputStream(file.getAbsolutePath());
    BufferedInputStream origin = new BufferedInputStream(fi, 2048);
    
    JarEntry entry = new JarEntry(makeName(parent, fileName));
    _output.putNextEntry(entry);
    
    int count = origin.read(data, 0, 2048);
    while (count != -1) {
      _output.write(data, 0, count);
      count = origin.read(data, 0, 2048);
    }
    
    origin.close();
  }
  
  /** Add the directory into the directory specified by parent
    * @param dir the directory to add
    * @param parent the path inside the jar that the directory should be added to
    */
  public void addDirectoryRecursive(File dir, String parent) {
    addDirectoryRecursiveHelper(dir, parent, new byte[2048], new FileFilter() {
      public boolean accept(File pathname) { return true; }
    });
  }
  
  /** Add the directory into the directory specified by parent
    * @param dir the directory to add
    * @param parent the path inside the jar that the directory should be added to
    * @param filter the filter used to filter the files
    */
  public void addDirectoryRecursive(File dir, String parent, FileFilter filter) {
    addDirectoryRecursiveHelper(dir, parent, new byte[2048], filter);
  }
  
  /** Add the contents of a directory that match a filter to the archive
   * @param dir the directory to add
   * @param parent the directory to add into
   * @param buffer a buffer that is 2048 bytes
   * @param filter the FileFilter to filter the files by
   * @return true on success, false on failure
   */
  private boolean addDirectoryRecursiveHelper(File dir, String parent, byte[] buffer, FileFilter filter) {
    try {
      File[] files = dir.listFiles(filter);
      BufferedInputStream origin = null;
      
      if( files == null ) // listFiles may return null if there"s an IO error
        return true;
      for (int i = 0; i < files.length; i++) {
        if( files[i].isFile() ) {
          origin = new BufferedInputStream(new FileInputStream(files[i]), 2048);
          
          JarEntry entry = new JarEntry(makeName(parent, files[i].getName()));
          _output.putNextEntry(entry);
          
          int count;
          while((count = origin.read(buffer, 0, 2048)) != -1) {
            _output.write(buffer, 0, count);
          }
          origin.close();
        }
        else if( files[i].isDirectory() ) {
          addDirectoryRecursiveHelper(files[i], makeName(parent, files[i].getName()),buffer,filter);
        }
      }
    } catch(Exception e) {
      e.printStackTrace();
    }
    return true;
  }
  
  /** Makes a directory in the jar file
   *
   * @param parent  The name of the parent that the directory is to be created in
   * @param dirName The name of the directory to be created
   * @return Returns true on success, false on failure
   */
  public boolean makeDirectory(String parent, String dirName) {
    JarEntry entry = new JarEntry(makeName(parent, dirName));
    try {
      _output.putNextEntry(entry);
    }
    catch (IOException e) {
      return false;
    }
    return true;
  }
  
  /** Close writing on the jar file
   */
  public void close() throws IOException {
    _output.flush();
    _output.close();
  }
}
class ManifestWriter {
  private List<String> _classPaths;
  private String _mainClass;
  private String _rawManifest;
  public static final Manifest DEFAULT = new ManifestWriter().getManifest();
  
  /** Create a new manifest file */
  public ManifestWriter() {
    _classPaths = new LinkedList<String>();
    _mainClass = null;
    _rawManifest = null;
  }
  
  /** Add a class path to the Manifest
    * @param path the path to be added
    */
  public void addClassPath(String path) {
    _classPaths.add(_classPaths.size(), path);
  }
  
  /** Set the main class of the Manifest
    * @param mainClass
    */
  public void setMainClass(String mainClass) {
    _mainClass = mainClass;
    _rawManifest = null;
  }
  
  public void setManifestContents(String rawManifest) {
    _rawManifest =  rawManifest;
    _mainClass = null;
  }
  
  /** Get an input stream to the contents of the manifest file
    * @return an InputStream whose contents are the contents of the Manifest file
    */
  protected InputStream getInputStream() {
    // NOTE: All significant lines in the manifest MUST end in the end of line character
    
    final StringBuilder sbuf = new StringBuilder();
    sbuf.append(Attributes.Name.MANIFEST_VERSION.toString());
    sbuf.append(": 1.0" + "\n");
    if( !_classPaths.isEmpty() ) {
      Iterator<String> iter = _classPaths.iterator();
      sbuf.append(Attributes.Name.CLASS_PATH.toString());
      sbuf.append(":");
      while (iter.hasNext()) {
        sbuf.append(" ");
        sbuf.append(iter.next());
      }
      sbuf.append("\n");
    }
    if( _mainClass != null ) {
      sbuf.append(Attributes.Name.MAIN_CLASS.toString());
      sbuf.append(": ");
      sbuf.append(_mainClass);
      sbuf.append("\n");
    }
    
    if(_rawManifest != null) {
      sbuf.append(_rawManifest); 
      
      if(!_rawManifest.endsWith("\n"))
        sbuf.append("\n");
    }
    
    try { return new ByteArrayInputStream(sbuf.toString().getBytes("UTF-8")); }
    catch (UnsupportedEncodingException e) { throw new RuntimeException(e); }
  }
  
  /** Get the Manifest object that this object created.
    * @return the Manifest that this builder created
    */
  public Manifest getManifest() {
    try {
      Manifest m = new Manifest();
      m.read(getInputStream());
      return m;
    }
    catch (IOException e) {
      e.printStackTrace();
      return null;
    }
  }
}





Jar Entry OutputStream

   
/*
 * The contents of this file are subject to the Sapient Public License
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://carbon.sf.net/License.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is The Carbon Component Framework.
 *
 * The Initial Developer of the Original Code is Sapient Corporation
 *
 * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
 */

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import sun.rmi.runtime.Log;
/**
 * An output stream that is used by EnhancedJarFile to write entries to a jar.
 * This implementation uses a ByteArrayOutputStream to buffer the output
 * until the stream is closed.  When the stream is closed, the output is written
 * to the jar.
 *
 * Copyright 2002 Sapient
 * @since carbon 1.0
 * @author Douglas Voet, April 2002
 * @version $Revision: 1.9 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)
 */
public class JarEntryOutputStream extends ByteArrayOutputStream {
    private EnhancedJarFile jar;
    private String jarEntryName;
    /**
     * Constructor
     *
     * @param jar the EnhancedJarFile that this instance will write to
     * @param jarEntryName the name of the entry to be written
     */
    public JarEntryOutputStream(
        EnhancedJarFile jar,
        String jarEntryName) {
        super();
        this.jarEntryName = jarEntryName;
        this.jar = jar;
    }
    /**
     * Closes the stream and writes entry to the jar
     */
    public void close() throws IOException {
        writeToJar();
        super.close();
    }
    /**
     * Writes the entry to a the jar file.  This is done by creating a
     * temporary jar file, copying the contents of the existing jar to the
     * temp jar, skipping the entry named by this.jarEntryName if it exists.
     * Then, if the stream was written to, then contents are written as a
     * new entry.  Last, a callback is made to the EnhancedJarFile to
     * swap the temp jar in for the old jar.
     */
    private void writeToJar() throws IOException {
        File jarDir = new File(this.jar.getName()).getParentFile();
        // create new jar
        File newJarFile = File.createTempFile("config", ".jar", jarDir);
        newJarFile.deleteOnExit();
        JarOutputStream jarOutputStream =
            new JarOutputStream(new FileOutputStream(newJarFile));
        try {
            Enumeration entries = this.jar.entries();
            // copy all current entries into the new jar
            while (entries.hasMoreElements()) {
                JarEntry nextEntry = (JarEntry) entries.nextElement();
                // skip the entry named jarEntryName
                if (!this.jarEntryName.equals(nextEntry.getName())) {
                    // the next 3 lines of code are a work around for
                    // bug 4682202 in the java.sun.ru bug parade, see:
                    // http://developer.java.sun.ru/developer/bugParade/bugs/4682202.html
                    JarEntry entryCopy = new JarEntry(nextEntry);
                    entryCopy.setCompressedSize(-1);
                    jarOutputStream.putNextEntry(entryCopy);
                    InputStream intputStream =
                        this.jar.getInputStream(nextEntry);
                    // write the data
                    for (int data = intputStream.read();
                        data != -1;
                        data = intputStream.read()) {
                        jarOutputStream.write(data);
                    }
                }
            }
            // write the new or modified entry to the jar
            if (size() > 0) {
                jarOutputStream.putNextEntry(new JarEntry(this.jarEntryName));
                jarOutputStream.write(super.buf, 0, size());
                jarOutputStream.closeEntry();
            }
        } finally {
            // close close everything up
            try {
                if (jarOutputStream != null) {
                    jarOutputStream.close();
                }
            } catch (IOException ioe) {
                // eat it, just wanted to close stream
            }
        }
        // swap the jar
        this.jar.swapJars(newJarFile);
    }
}
/*
 * The contents of this file are subject to the Sapient Public License
 * Version 1.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://carbon.sf.net/License.html.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is The Carbon Component Framework.
 *
 * The Initial Developer of the Original Code is Sapient Corporation
 *
 * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
 */

/**
 * This class enhances functionality of java.util.jar.JarFile.
 * Additional functionality includes jar entry removal, the ability to list
 * the entries within a directory within the jar, and the ability to get
 * an output stream for modifying extisting entries.
 *
 * @see java.util.jar.JarFile
 *
 * Copyright 2002 Sapient
 * @since carbon 1.0
 * @author Doug Voet, April 2002
 * @version $Revision: 1.11 $ ($Author: dvoet $)
 */
class EnhancedJarFile {
    public static final String JAR_DELIMETER = "/";
 
    private JarFile jar;
    /**
     * @see java.util.jar.JarFile#JarFile(java.lang.String)
     */
    public EnhancedJarFile(String name) throws IOException {
        this.jar = new JarFile(name);
    }
    /**
     * @see java.util.jar.JarFile#JarFile(java.lang.String, boolean)
     */
    public EnhancedJarFile(String name, boolean verify) throws IOException {
        this.jar = new JarFile(name, verify);
    }
    /**
     * @see java.util.jar.JarFile#JarFile(java.io.File)
     */
    public EnhancedJarFile(File file) throws IOException {
        this.jar = new JarFile(file);
    }
    /**
     * @see java.util.jar.JarFile#JarFile(java.io.File, boolean)
     */
    public EnhancedJarFile(File file, boolean verify) throws IOException {
        this.jar = new JarFile(file, verify);
    }
    /**
     * @see java.util.jar.JarFile#JarFile(java.io.File, boolean, int)
     */
    public EnhancedJarFile(File file, boolean verify, int mode)
        throws IOException {
        this.jar = new JarFile(file, verify, mode);
    }
    /**
     * Returns a list of entries that are
     * immediately below the entry named by entryName in the jar"s directory
     * structure.
     *
     * @param entryName the name of the directory entry name
     * @return List a list of java.util.jar.JarEntry objects that are
     * immediately below the entry named by entryName in the jar"s directory
     * structure.
     */
    public List listSubEntries(String entryName) {
        Enumeration entries = jar.entries();
        List subEntries = new ArrayList();
        while(entries.hasMoreElements()) {
            JarEntry nextEntry = (JarEntry) entries.nextElement();
            if (nextEntry.getName().startsWith(entryName)) {
                // the next entry name starts with the entryName so it
                // is a potential sub entry
                // tokenize the rest of the next entry name to see how
                // many tokens exist
                StringTokenizer tokenizer = new StringTokenizer(
                    nextEntry.getName().substring(entryName.length()),
                    EnhancedJarFile.JAR_DELIMETER);
                if (tokenizer.countTokens() == 1) {
                    // only 1 token exists, so it is a sub-entry
                    subEntries.add(nextEntry);
                }
            }
        }
        return subEntries;
    }
    /**
     * Creates a new output entry stream within the jar.  The entry named
     * will be created if it does not exist within the jar already.
     *
     * @param entryName name of the entry for which to create an output
     * stream.
     * @return JarEntryOutputStream
     */
    public JarEntryOutputStream getEntryOutputStream(String entryName) {
        return new JarEntryOutputStream(this, entryName);
    }
    /**
     * Removes the given entry from the jar.  If the entry does not exist,
     * the method returns without doing anything.
     *
     * @param entry entry to be removed
     * @throws IOException if there is a problem writing the changes
     * to the jar
     */
    public void removeEntry(JarEntry entry) throws IOException {
        // opens an output stream and closes it without writing anything to it
        if (entry != null && getEntry(entry.getName()) != null) {
            JarEntryOutputStream outputStream =
                new JarEntryOutputStream(this, entry.getName());
            outputStream.close();
        }
    }
    /**
     * @see java.util.jar.JarFile#entries()
     */
    public Enumeration entries() {
        return this.jar.entries();
    }
    /**
     * @see java.util.jar.JarFile#getEntry(java.lang.String)
     */
    public ZipEntry getEntry(String arg0) {
        return this.jar.getEntry(arg0);
    }
    /**
     * @see java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
     */
    public InputStream getInputStream(ZipEntry arg0) throws IOException {
        return this.jar.getInputStream(arg0);
    }
    /**
     * @see java.util.jar.JarFile#getJarEntry(java.lang.String)
     */
    public JarEntry getJarEntry(String arg0) {
        return this.jar.getJarEntry(arg0);
    }
    /**
     * @see java.util.jar.JarFile#getManifest()
     */
    public Manifest getManifest() throws IOException {
        return this.jar.getManifest();
    }
    /**
     * @see java.util.zip.ZipFile#close()
     */
    public void close() throws IOException {
        this.jar.close();
    }
    /**
     * @see java.util.zip.ZipFile#getName()
     */
    public String getName() {
        return this.jar.getName();
    }
    /**
     * @see java.util.zip.ZipFile#size()
     */
    public int size() {
        return this.jar.size();
    }
    /**
     * Utility method used to swap the underlying jar file out for the new one.
     * This method closes the old jar file, deletes it, moves the new jar
     * file to the location where the old one used to be and opens it.
     * <p>
     * This is used when modifying the jar (removal, addition, or changes
     * of entries)
     *
     * @param newJarFile the file object pointing to the new jar file
     */
    void swapJars(File newJarFile) throws IOException {
        File oldJarFile = new File(getName());
        this.jar.close();
        oldJarFile.delete();
        if (newJarFile.renameTo(oldJarFile)) {
            this.jar = new JarFile(oldJarFile);
        } else {
            throw new IOException();
        }
    }
}





Jar file helper to deployment

 
/**
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.security.cert.Certificate;
/**
 * @version $Rev: 726699 $ $Date: 2008-12-15 06:30:36 -0800 (Mon, 15 Dec 2008) $
 */
public class UnpackedJarFile extends JarFile {
    private final File baseDir;
    private boolean manifestLoaded = false;
    private Manifest manifest;
    public UnpackedJarFile(File baseDir) throws IOException {
        super(DeploymentUtil.DUMMY_JAR_FILE);
        this.baseDir = baseDir;
        if (!baseDir.isDirectory()) {
            throw new IOException("File must be a directory: file=" + baseDir.getAbsolutePath());
        }
    }
    public File getBaseDir() {
        return baseDir;
    }
    public Manifest getManifest() throws IOException {
        if (!manifestLoaded) {
            File manifestFile = getFile("META-INF/MANIFEST.MF");
            if (manifestFile != null && manifestFile.isFile()) {
                FileInputStream in = null;
                try {
                    in = new FileInputStream(manifestFile);
                    manifest = new Manifest(in);
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            // ignore
                        }
                    }
                }
            }
            manifestLoaded = true;
        }
        return manifest;
    }
    public UnpackedJarEntry getUnpackedJarEntry(String name) {
        File file = getFile(name);
        if (file == null) {
            return null;
        }
        return new UnpackedJarEntry(name, file, getManifestSafe());
    }
    public JarEntry getJarEntry(String name) {
        return getUnpackedJarEntry(name);
    }
    public ZipEntry getEntry(String name) {
        return getUnpackedJarEntry(name);
    }
    public Enumeration entries() {
        Collection files = DeploymentUtil.listRecursiveFiles(baseDir);
        Manifest manifest = getManifestSafe();
        LinkedList entries = new LinkedList();
        URI baseURI = baseDir.getAbsoluteFile().toURI();
        for (Iterator iterator = files.iterator(); iterator.hasNext();) {
            File entryFile = ((File) iterator.next()).getAbsoluteFile();
            URI entryURI = entryFile.toURI();
            URI relativeURI = baseURI.relativize(entryURI);
            entries.add(new UnpackedJarEntry(relativeURI.getPath(), entryFile, manifest));
        }
        return Collections.enumeration(entries);
    }
    public InputStream getInputStream(ZipEntry zipEntry) throws IOException {
        File file;
        if (zipEntry instanceof UnpackedJarEntry) {
            file = ((UnpackedJarEntry)zipEntry).getFile();
        } else {
            file = getFile(zipEntry.getName());
        }
        if (file == null) {
            throw new IOException("Entry not found: name=" + zipEntry.getName());
        } else if (file.isDirectory()) {
            return new DeploymentUtil.EmptyInputStream();
        }
        return new FileInputStream(file);
    }
    public String getName() {
        return baseDir.getAbsolutePath();
    }
    /**
     * Always returns -1.
     * @return -1
     */
    public int size() {
        return -1;
    }
    public void close() throws IOException {
        try {
            super.close();
        } catch(IOException ignored) {
        }
    }
    protected void finalize() throws IOException {
    }
    public File getFile(String name) {
        File file = new File(baseDir, name);
        if (!file.exists()) {
            return null;
        }
        return file;
    }
    private Manifest getManifestSafe() {
        Manifest manifest = null;
        try {
            manifest = getManifest();
        } catch (IOException e) {
            // ignore
        }
        return manifest;
    }
}
/**
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/**
 * @version $Rev: 617659 $ $Date: 2008-02-01 13:29:25 -0800 (Fri, 01 Feb 2008) $
 */
 final class DeploymentUtil {
    private DeploymentUtil() {
    }
    public static final File DUMMY_JAR_FILE;
    private static final boolean jarUrlRewrite;
    static {
        jarUrlRewrite = new Boolean(System.getProperty("org.apache.geronimo.deployment.util.DeploymentUtil.jarUrlRewrite", "false"));
        try {
            DUMMY_JAR_FILE = DeploymentUtil.createTempFile();
            new JarOutputStream(new FileOutputStream(DeploymentUtil.DUMMY_JAR_FILE), new Manifest()).close();
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    // be careful to clean up the temp directory
    public static File createTempDir() throws IOException {
        File tempDir = File.createTempFile("geronimo-deploymentUtil", ".tmpdir");
        tempDir.delete();
        tempDir.mkdirs();
        return tempDir;
    }
    // be careful to clean up the temp file... we tell the vm to delete this on exit
    // but VMs can"t be trusted to acutally delete the file
    public static File createTempFile() throws IOException {
        File tempFile = File.createTempFile("geronimo-deploymentUtil", ".tmpdir");
        tempFile.deleteOnExit();
        return tempFile;
    }
    
    // be careful to clean up the temp file... we tell the vm to delete this on exit
    // but VMs can"t be trusted to acutally delete the file
    private static File createTempFile(String extension) throws IOException {
        File tempFile = File.createTempFile("geronimo-deploymentUtil", extension == null? ".tmpdir": extension);
        tempFile.deleteOnExit();
        return tempFile;
    }

    public static void copyFile(File source, File destination) throws IOException {
        File destinationDir = destination.getParentFile();
        if (!destinationDir.exists() && !destinationDir.mkdirs()) {
            throw new java.io.IOException("Cannot create directory : " + destinationDir);
        }
        
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(source);
            out = new FileOutputStream(destination);
            writeAll(in, out);
        } finally {
            close(in);
            close(out);
        }
    }
    private static void writeAll(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[4096];
        int count;
        while ((count = in.read(buffer)) > 0) {
            out.write(buffer, 0, count);
        }
        out.flush();
    }
    public static File toTempFile(JarFile jarFile, String path) throws IOException {
        return toTempFile(createJarURL(jarFile, path));
    }
    public static File toTempFile(URL url) throws IOException {
        InputStream in = null;
        OutputStream out = null;
        JarFile jarFile = null;
        try {
            if(url.getProtocol().equalsIgnoreCase("jar")) {
                // url.openStream() locks the jar file and does not release the lock even after the stream is closed.
                // This problem is avoided by using JarFile APIs.
                File file = new File(url.getFile().substring(5, url.getFile().indexOf("!/")));
                String path = url.getFile().substring(url.getFile().indexOf("!/")+2);
                jarFile = new JarFile(file);
                JarEntry jarEntry = jarFile.getJarEntry(path);
                if(jarEntry != null) {
                    in = jarFile.getInputStream(jarEntry);
                } else {
                    throw new FileNotFoundException("JarEntry "+path+" not found in "+file);
                }
            } else {
                in = url.openStream();
            }
            int index = url.getPath().lastIndexOf(".");
            String extension = null;
            if (index > 0) {
                extension = url.getPath().substring(index);
            }
            File tempFile = createTempFile(extension);
            out = new FileOutputStream(tempFile);
            writeAll(in, out);
            return tempFile;
        } finally {
            close(out);
            close(in);
            close(jarFile);
        }
    }
    public static String readAll(URL url) throws IOException {
        Reader reader = null;
        JarFile jarFile = null;
        try {
            if(url.getProtocol().equalsIgnoreCase("jar")) {
                // url.openStream() locks the jar file and does not release the lock even after the stream is closed.
                // This problem is avoided by using JarFile APIs.
                File file = new File(url.getFile().substring(5, url.getFile().indexOf("!/")));
                String path = url.getFile().substring(url.getFile().indexOf("!/")+2);
                jarFile = new JarFile(file);
                JarEntry jarEntry = jarFile.getJarEntry(path);
                if(jarEntry != null) {
                    reader = new InputStreamReader(jarFile.getInputStream(jarEntry));
                } else {
                    throw new FileNotFoundException("JarEntry "+path+" not found in "+file);
                }
            } else {
                reader = new InputStreamReader(url.openStream());
            }
            char[] buffer = new char[4000];
            StringBuffer out = new StringBuffer();
            for(int count = reader.read(buffer); count >= 0; count = reader.read(buffer)) {
                out.append(buffer, 0, count);
            }
            return out.toString();
        } finally {
            close(reader);
            close(jarFile);
        }
    }
    public static File toFile(JarFile jarFile) throws IOException {
        if (jarFile instanceof UnpackedJarFile) {
            return ((UnpackedJarFile) jarFile).getBaseDir();
        } else {
          throw new IOException("jarFile is not a directory");
        }
    }
    // be careful with this method as it can leave a temp lying around
    public static File toFile(JarFile jarFile, String path) throws IOException {
        if (jarFile instanceof UnpackedJarFile) {
            File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
            File file = new File(baseDir, path);
            if (!file.isFile()) {
                throw new IOException("No such file: " + file.getAbsolutePath());
            }
            return file;
        } else {
            String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
            return toTempFile(new URL(urlString));
        }
    }
    public static URL createJarURL(JarFile jarFile, String path) throws MalformedURLException {
        if (jarFile instanceof NestedJarFile) {
            NestedJarFile nestedJar = (NestedJarFile) jarFile;
            if (nestedJar.isUnpacked()) {
                JarFile baseJar = nestedJar.getBaseJar();
                String basePath = nestedJar.getBasePath();
                if (baseJar instanceof UnpackedJarFile) {
                    File baseDir = ((UnpackedJarFile) baseJar).getBaseDir();
                    baseDir = new File(baseDir, basePath);
                    return new File(baseDir, path).toURL();
                }
            }
        }
        
        if (jarFile instanceof UnpackedJarFile) {
            File baseDir = ((UnpackedJarFile) jarFile).getBaseDir();
            return new File(baseDir, path).toURL();
        } else {
            String urlString = "jar:" + new File(jarFile.getName()).toURL() + "!/" + path;
            if(jarUrlRewrite) {
                // To prevent the lockout of archive, instead of returning a jar url, write the content to a
                // temp file and return the url of that file.
                File tempFile = null;
                try {
                    tempFile = toTempFile(new URL(urlString));
                } catch (IOException e) {
                    // The JarEntry does not exist!
                    // Return url of a file that does not exist.
                    try {
                        tempFile = createTempFile();
                        tempFile.delete();
                    } catch (IOException ignored) {
                    }
                 }
                return tempFile.toURL();
            } else {
                return new URL(urlString);
            }
        }
    }
    public static JarFile createJarFile(File jarFile) throws IOException {
        if (jarFile.isDirectory()) {
            return new UnpackedJarFile(jarFile);
        } else {
            return new JarFile(jarFile);
        }
    }
    public static void copyToPackedJar(JarFile inputJar, File outputFile) throws IOException {
        if (inputJar.getClass() == JarFile.class) {
            // this is a plain old jar... nothign special
            copyFile(new File(inputJar.getName()), outputFile);
        } else if (inputJar instanceof NestedJarFile && ((NestedJarFile)inputJar).isPacked()) {
            NestedJarFile nestedJarFile = (NestedJarFile)inputJar;
            JarFile baseJar = nestedJarFile.getBaseJar();
            String basePath = nestedJarFile.getBasePath();
            if (baseJar instanceof UnpackedJarFile) {
                // our target jar is just a file in upacked jar (a plain old directory)... now
                // we just need to find where it is and copy it to the outptu
                copyFile(((UnpackedJarFile)baseJar).getFile(basePath), outputFile);
            } else {
                // out target is just a plain old jar file directly accessabel from the file system
                copyFile(new File(baseJar.getName()), outputFile);
            }
        } else {
            // copy out the module contents to a standalone jar file (entry by entry)
            JarOutputStream out = null;
            try {
                out = new JarOutputStream(new FileOutputStream(outputFile));
                byte[] buffer = new byte[4096];
                Enumeration entries = inputJar.entries();
                while (entries.hasMoreElements()) {
                    ZipEntry entry = (ZipEntry) entries.nextElement();
                    InputStream in = inputJar.getInputStream(entry);
                    try {
                        out.putNextEntry(new ZipEntry(entry.getName()));
                        try {
                            int count;
                            while ((count = in.read(buffer)) > 0) {
                                out.write(buffer, 0, count);
                            }
                        } finally {
                            out.closeEntry();
                        }
                    } finally {
                        close(in);
                    }
                }
            } finally {
                close(out);
            }
        }
    }
    public static void jarDirectory(File sourceDirecotry, File destinationFile) throws IOException {
        JarFile inputJar = new UnpackedJarFile(sourceDirecotry);
        try {
            copyToPackedJar(inputJar, destinationFile);
        } finally {
            close(inputJar);
        }
    }
    private static void createDirectory(File dir) throws IOException {
        if (dir != null && !dir.exists()) {
            boolean success = dir.mkdirs();
            if (!success) {
                throw new IOException("Cannot create directory " + dir.getAbsolutePath());
            }
        }
    }
    public static void unzipToDirectory(ZipFile zipFile, File destDir) throws IOException {
        Enumeration entries = zipFile.entries();
        try {
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                if (entry.isDirectory()) {
                    File dir = new File(destDir, entry.getName());
                    createDirectory(dir);
                } else {
                    File file = new File(destDir, entry.getName());
                    createDirectory(file.getParentFile());
                    OutputStream out = null;
                    InputStream in = null;
                    try {
                        out = new BufferedOutputStream(new FileOutputStream(file));
                        in = zipFile.getInputStream(entry);
                        writeAll(in, out);
                    } finally {
                        if (null != out) {
                            out.close();
                        }
                        if (null != in) {
                            in.close();
                        }
                    }
                }
            }
        } finally {
            zipFile.close();
        }
    }
    
    
    public static boolean recursiveDelete(File root, Collection<String> unableToDeleteCollection) {
        if (root == null) {
            return true;
        }
        if (root.isDirectory()) {
            File[] files = root.listFiles();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    File file = files[i];
                    if (file.isDirectory()) {
                        recursiveDelete(file, unableToDeleteCollection);
                    } else {
                        if (!file.delete() && unableToDeleteCollection != null) {
                            unableToDeleteCollection.add(file.getAbsolutePath());    
                        }
                    }
                    // help out the GC of file handles by nulling the references
                    files[i] = null;
                }
            }
        }
        boolean rootDeleteStatus;
        if (!(rootDeleteStatus = root.delete()) && unableToDeleteCollection != null) 
          unableToDeleteCollection.add(root.getAbsolutePath());
        
        return rootDeleteStatus;
    }
    
    public static boolean recursiveDelete(File root) {
        return recursiveDelete(root, null);
    }
    public static Collection<File> listRecursiveFiles(File file) {
        Collection<File> list = new ArrayList<File>();
        listRecursiveFiles(file, list);
        return Collections.unmodifiableCollection(list);
    }
    public static void listRecursiveFiles(File file, Collection<File> collection) {
        File[] files = file.listFiles();
        if ( null == files ) {
            return;
        }
        for (File file1 : files) {
            collection.add(file1);
            if (file1.isDirectory()) {
                listRecursiveFiles(file1, collection);
            }
        }
    }
    public static void flush(OutputStream thing) {
        if (thing != null) {
            try {
                thing.flush();
            } catch(Exception ignored) {
            }
        }
    }
    public static void flush(Writer thing) {
        if (thing != null) {
            try {
                thing.flush();
            } catch(Exception ignored) {
            }
        }
    }
    public static void close(JarFile thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch(Exception ignored) {
            }
        }
    }
    public static void close(InputStream thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch(Exception ignored) {
            }
        }
    }
    public static void close(OutputStream thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch(Exception ignored) {
            }
        }
    }
    public static void close(Reader thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch(Exception ignored) {
            }
        }
    }
    public static void close(Writer thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch(Exception ignored) {
            }
        }
    }
    public static final class EmptyInputStream extends InputStream {
        public int read() {
            return -1;
        }
        public int read(byte b[])  {
            return -1;
        }
        public int read(byte b[], int off, int len) {
            return -1;
        }
        public long skip(long n) {
            return 0;
        }
        public int available() {
            return 0;
        }
        public void close() {
        }
        public synchronized void mark(int readlimit) {
        }
        public synchronized void reset() {
        }
        public boolean markSupported() {
            return false;
        }
    }
}
 /**
  *  Licensed to the Apache Software Foundation (ASF) under one or more
  *  contributor license agreements.  See the NOTICE file distributed with
  *  this work for additional information regarding copyright ownership.
  *  The ASF licenses this file to You under the Apache License, Version 2.0
  *  (the "License"); you may not use this file except in compliance with
  *  the License.  You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */

 /**
  * @version $Rev: 726699 $ $Date: 2008-12-15 06:30:36 -0800 (Mon, 15 Dec 2008) $
  */
 class NestedJarFile extends JarFile {
     private JarFile baseJar;
     private String basePath;
     private boolean isClosed = false;
     private boolean manifestLoaded = false;
     private Manifest manifest;
     private File tempFile;
     public NestedJarFile(JarFile jarFile, String path) throws IOException {
         super(DeploymentUtil.DUMMY_JAR_FILE);
         // verify that the jar actually contains that path
         JarEntry targetEntry = jarFile.getJarEntry(path + "/");
         if (targetEntry == null) {
             targetEntry = jarFile.getJarEntry(path);
             if (targetEntry == null) {
                 throw new IOException("Jar entry does not exist: jarFile=" + jarFile.getName() + ", path=" + path);
             }
         }
         if (targetEntry.isDirectory()) {
          if(targetEntry instanceof UnpackedJarEntry) {
            //unpacked nested module inside unpacked ear
            File targetFile = ((UnpackedJarEntry) targetEntry).getFile();
            baseJar = new UnpackedJarFile(targetFile);
                 basePath = "";
          } else {
            baseJar = jarFile;
            if (!path.endsWith("/")) {
                     path += "/";
                 }
                 basePath = path;
          }
         } else {
             if (targetEntry instanceof UnpackedJarEntry) {
                 // for unpacked jars we don"t need to copy the jar file
                 // out to a temp directory, since it is already available
                 // as a raw file
                 File targetFile = ((UnpackedJarEntry) targetEntry).getFile();
                 baseJar = new JarFile(targetFile);
                 basePath = "";
             } else {
                 tempFile = DeploymentUtil.toFile(jarFile, targetEntry.getName());
                 baseJar = new JarFile(tempFile);
                 basePath = "";
             }
         }
     }
     public boolean isUnpacked() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return ( basePath.length() > 0 ) ||
                ( ( baseJar != null ) && ( baseJar instanceof UnpackedJarFile ) );
     }
     public boolean isPacked() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return ( basePath.length() == 0 ) &&
                ( ( baseJar == null ) || !( baseJar instanceof UnpackedJarFile ) );
     }
     public JarFile getBaseJar() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return baseJar;
     }
     public String getBasePath() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return basePath;
     }
     public Manifest getManifest() throws IOException {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         if (!manifestLoaded) {
             JarEntry manifestEntry = getBaseEntry("META-INF/MANIFEST.MF");
             if (manifestEntry != null && !manifestEntry.isDirectory()) {
                 InputStream in = null;
                 try {
                     in = baseJar.getInputStream(manifestEntry);
                     manifest = new Manifest(in);
                 } finally {
                     if (in != null) {
                         try {
                             in.close();
                         } catch (IOException e) {
                             // ignore
                         }
                     }
                 }
             }
             manifestLoaded = true;
         }
         return manifest;
     }
     public NestedJarEntry getNestedJarEntry(String name) {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         JarEntry baseEntry = getBaseEntry(name);
         if (baseEntry == null) {
             return null;
         }
         return new NestedJarEntry(name, baseEntry, getManifestSafe());
     }
     public JarEntry getJarEntry(String name) {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return getNestedJarEntry(name);
     }
     public ZipEntry getEntry(String name) {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return getNestedJarEntry(name);
     }
     public Enumeration entries() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         Collection baseEntries = Collections.list(baseJar.entries());
         Collection entries = new LinkedList();
         for (Iterator iterator = baseEntries.iterator(); iterator.hasNext();) {
             JarEntry baseEntry = (JarEntry) iterator.next();
             String path = baseEntry.getName();
             if (path.startsWith(basePath)) {
                 entries.add(new NestedJarEntry(path.substring(basePath.length()), baseEntry, getManifestSafe()));
             }
         }
         return Collections.enumeration(entries);
     }
     public InputStream getInputStream(ZipEntry zipEntry) throws IOException {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         JarEntry baseEntry;
         if (zipEntry instanceof NestedJarEntry) {
             baseEntry = ((NestedJarEntry)zipEntry).getBaseEntry();
         } else {
             baseEntry = getBaseEntry(zipEntry.getName());
         }
         if (baseEntry == null) {
             throw new IOException("Entry not found: name=" + zipEntry.getName());
         } else if (baseEntry.isDirectory()) {
             return new DeploymentUtil.EmptyInputStream();
         }
         return baseJar.getInputStream(baseEntry);
     }
     public String getName() {
         return baseJar.getName();
     }
     /**
      * Always returns -1.
      * @return -1
      */
     public int size() {
         if (isClosed) {
             throw new IllegalStateException("NestedJarFile is closed");
         }
         return -1;
     }
     public void close() throws IOException {
         if (isClosed) {
             return;
         }
         try {
             try {
                 super.close();
             } catch(IOException ignored) {
             }
             if (baseJar != null && basePath.length() == 0) {
                 // baseJar is created by us.  We should be closing it too.
                 baseJar.close();
             }
         } finally {
             isClosed = true;
             baseJar = null;
             basePath = null;
             manifestLoaded = false;
             manifest = null;
             if (tempFile != null) {
                 tempFile.delete();
                 tempFile = null;
             }
         }
     }
     protected void finalize() throws IOException {
         close();
     }
     private JarEntry getBaseEntry(String name) {
         return baseJar.getJarEntry(basePath + name);
     }
     private Manifest getManifestSafe() {
         Manifest manifest = null;
         try {
             manifest = getManifest();
         } catch (IOException e) {
             // ignore
         }
         return manifest;
     }
 }
 /**
  *  Licensed to the Apache Software Foundation (ASF) under one or more
  *  contributor license agreements.  See the NOTICE file distributed with
  *  this work for additional information regarding copyright ownership.
  *  The ASF licenses this file to You under the Apache License, Version 2.0
  *  (the "License"); you may not use this file except in compliance with
  *  the License.  You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */

 /**
  * @version $Rev: 476049 $ $Date: 2006-11-16 20:35:17 -0800 (Thu, 16 Nov 2006) $
  */
  class NestedJarEntry extends JarEntry {
     private final JarEntry baseEntry;
     private final Manifest manifest;
     public NestedJarEntry(String name, JarEntry baseEntry, Manifest manifest) {
         super(name);
         this.baseEntry = baseEntry;
         this.manifest = manifest;
     }
     public JarEntry getBaseEntry() {
         return baseEntry;
     }
     public Attributes getAttributes() throws IOException {
         if (manifest == null) {
             return null;
         }
         return manifest.getAttributes(getName());
     }
 
     public long getTime() {
         return baseEntry.getTime();
     }
     public void setTime(long time) {
         baseEntry.setTime(time);
     }
     public long getSize() {
         return baseEntry.getSize();
     }
     public void setSize(long size) {
         baseEntry.setSize(size);
     }
     public long getCompressedSize() {
         return baseEntry.getCompressedSize();
     }
     public void setCompressedSize(long csize) {
         baseEntry.setCompressedSize(csize);
     }
     public long getCrc() {
         return baseEntry.getCrc();
     }
     public void setCrc(long crc) {
         baseEntry.setCrc(crc);
     }
     public int getMethod() {
         return baseEntry.getMethod();
     }
     public void setMethod(int method) {
         baseEntry.setMethod(method);
     }
     public byte[] getExtra() {
         return baseEntry.getExtra();
     }
     public void setExtra(byte[] extra) {
         baseEntry.setExtra(extra);
     }
     public String getComment() {
         return baseEntry.getComment();
     }
     public void setComment(String comment) {
         baseEntry.setComment(comment);
     }
     public boolean isDirectory() {
         return baseEntry.isDirectory();
     }
     public String toString() {
         return baseEntry.toString();
     }
     public int hashCode() {
         return baseEntry.hashCode();
     }
     public Object clone() {
         return new NestedJarEntry(getName(), baseEntry, manifest);
     }
 }
  /**
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */

  /**
   * @version $Rev: 476049 $ $Date: 2006-11-16 20:35:17 -0800 (Thu, 16 Nov 2006) $
   */
  class UnpackedJarEntry extends JarEntry {
      private final File file;
      private final Manifest manifest;
      public UnpackedJarEntry(String name, File file, Manifest manifest) {
          super(name);
          this.file = file;
          this.manifest = manifest;
      }
      public File getFile() {
          return file;
      }
      public Attributes getAttributes() throws IOException {
          if (manifest == null) {
              return null;
          }
          return manifest.getAttributes(getName());
      }

      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param time ignored
       * @throws UnsupportedOperationException always
       */
      public void setTime(long time) throws UnsupportedOperationException {
          throw new UnsupportedOperationException("Can not change the time of unpacked jar entry");
      }
      public long getTime() {
          return file.lastModified();
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param size ignored
       * @throws UnsupportedOperationException always
       */
      public void setSize(long size) throws UnsupportedOperationException {
          throw new UnsupportedOperationException("Can not change the size of unpacked jar entry");
      }
      public long getSize() {
          if (file.isDirectory()) {
              return -1;
          } else {
              return file.length();
          }
      }
      /**
       * An unpacked jar is not compressed, so this method returns getSize().
       * @return getSize()
       */
      public long getCompressedSize() {
          return getSize();
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param compressedSize ignored
       * @throws UnsupportedOperationException always
       */
      public void setCompressedSize(long compressedSize) {
          throw new UnsupportedOperationException("Can not change the compressed size of unpacked jar entry");
      }
      public long getCrc() {
          return super.getCrc();    //To change body of overridden methods use File | Settings | File Templates.
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param crc ignored
       * @throws UnsupportedOperationException always
       */
      public void setCrc(long crc) {
          throw new UnsupportedOperationException("Can not change the crc of unpacked jar entry");
      }
      public int getMethod() {
          return ZipEntry.STORED;
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param method ignored
       * @throws UnsupportedOperationException always
       */
      public void setMethod(int method) {
          throw new UnsupportedOperationException("Can not change the method of unpacked jar entry");
      }
      /**
       * Always returns null.
       * @return null
       */
      public byte[] getExtra() {
          return null;
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param extra ignored
       * @throws UnsupportedOperationException always
       */
      public void setExtra(byte[] extra) {
          throw new UnsupportedOperationException("Can not change the extra data of unpacked jar entry");
      }
      /**
       * Always returns null.
       * @return null
       */
      public String getComment() {
          return null;
      }
      /**
       * An unpacked jar is read only, so this method always throws an UnsupportedOperationException.
       * @param comment ignored
       * @throws UnsupportedOperationException always
       */
      public void setComment(String comment) {
          throw new UnsupportedOperationException("Can not change the comment of unpacked jar entry");
      }
      public boolean isDirectory() {
          return file.isDirectory();
      }
      public Object clone() {
          return new UnpackedJarEntry(getName(), file, manifest);
      }
  }





Jarring and unjarring files and directories.

 

/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
/**
 * Provides utility services for jarring and unjarring files and directories.
 * Note that a given instance of JarHelper is not threadsafe with respect to
 * multiple jar operations.
 * 
 * @author Patrick Calahan <pcal@bea.ru>
 */
public class JarHelper {
  // Constants
  private static final int BUFFER_SIZE = 2156;
  // Variables
  private byte[] mBuffer = new byte[BUFFER_SIZE];
  private int mByteCount = 0;
  private boolean mVerbose = false;
  private String mDestJarName = "";
  // Constructor
  /**
   * Instantiates a new JarHelper.
   */
  public JarHelper() {
  }
  // Public methods
  /**
   * Jars a given directory or single file into a JarOutputStream.
   */
  public void jarDir(File dirOrFile2Jar, File destJar) throws IOException {
    if (dirOrFile2Jar == null || destJar == null)
      throw new IllegalArgumentException();
    mDestJarName = destJar.getCanonicalPath();
    FileOutputStream fout = new FileOutputStream(destJar);
    JarOutputStream jout = new JarOutputStream(fout);
    // jout.setLevel(0);
    try {
      jarDir(dirOrFile2Jar, jout, null);
    } catch (IOException ioe) {
      throw ioe;
    } finally {
      jout.close();
      fout.close();
    }
  }
  /**
   * Unjars a given jar file into a given directory.
   */
  public void unjarDir(File jarFile, File destDir) throws IOException {
    BufferedOutputStream dest = null;
    FileInputStream fis = new FileInputStream(jarFile);
    unjar(fis, destDir);
  }
  /**
   * Given an InputStream on a jar file, unjars the contents into the given
   * directory.
   */
  public void unjar(InputStream in, File destDir) throws IOException {
    BufferedOutputStream dest = null;
    JarInputStream jis = new JarInputStream(in);
    JarEntry entry;
    while ((entry = jis.getNextJarEntry()) != null) {
      if (entry.isDirectory()) {
        File dir = new File(destDir, entry.getName());
        dir.mkdir();
        if (entry.getTime() != -1)
          dir.setLastModified(entry.getTime());
        continue;
      }
      int count;
      byte data[] = new byte[BUFFER_SIZE];
      File destFile = new File(destDir, entry.getName());
      if (mVerbose)
        System.out.println("unjarring " + destFile + " from " + entry.getName());
      FileOutputStream fos = new FileOutputStream(destFile);
      dest = new BufferedOutputStream(fos, BUFFER_SIZE);
      while ((count = jis.read(data, 0, BUFFER_SIZE)) != -1) {
        dest.write(data, 0, count);
      }
      dest.flush();
      dest.close();
      if (entry.getTime() != -1)
        destFile.setLastModified(entry.getTime());
    }
    jis.close();
  }
  public void setVerbose(boolean b) {
    mVerbose = b;
  }
  // Private methods
  private static final char SEP = "/";
  /**
   * Recursively jars up the given path under the given directory.
   */
  private void jarDir(File dirOrFile2jar, JarOutputStream jos, String path) throws IOException {
    if (mVerbose)
      System.out.println("checking " + dirOrFile2jar);
    if (dirOrFile2jar.isDirectory()) {
      String[] dirList = dirOrFile2jar.list();
      String subPath = (path == null) ? "" : (path + dirOrFile2jar.getName() + SEP);
      if (path != null) {
        JarEntry je = new JarEntry(subPath);
        je.setTime(dirOrFile2jar.lastModified());
        jos.putNextEntry(je);
        jos.flush();
        jos.closeEntry();
      }
      for (int i = 0; i < dirList.length; i++) {
        File f = new File(dirOrFile2jar, dirList[i]);
        jarDir(f, jos, subPath);
      }
    } else {
      if (dirOrFile2jar.getCanonicalPath().equals(mDestJarName)) {
        if (mVerbose)
          System.out.println("skipping " + dirOrFile2jar.getPath());
        return;
      }
      if (mVerbose)
        System.out.println("adding " + dirOrFile2jar.getPath());
      FileInputStream fis = new FileInputStream(dirOrFile2jar);
      try {
        JarEntry entry = new JarEntry(path + dirOrFile2jar.getName());
        entry.setTime(dirOrFile2jar.lastModified());
        jos.putNextEntry(entry);
        while ((mByteCount = fis.read(mBuffer)) != -1) {
          jos.write(mBuffer, 0, mByteCount);
          if (mVerbose)
            System.out.println("wrote " + mByteCount + " bytes");
        }
        jos.flush();
        jos.closeEntry();
      } catch (IOException ioe) {
        throw ioe;
      } finally {
        fis.close();
      }
    }
  }
  // for debugging
  public static void main(String[] args) throws IOException {
    if (args.length < 2) {
      System.err.println("Usage: JarHelper jarname.jar directory");
      return;
    }
    JarHelper jarHelper = new JarHelper();
    jarHelper.mVerbose = true;
    File destJar = new File(args[0]);
    File dirOrFile2Jar = new File(args[1]);
    jarHelper.jarDir(dirOrFile2Jar, destJar);
  }
}





List files in a jar file

    
   import java.io.*;
   import java.util.*;
   import java.util.jar.*;
   public class JarDir {
     public static void main (String args[]) 
         throws IOException {
       JarFile jarFile = new JarFile("yourJarFileName.jar");
       Enumeration enum = jarFile.entries();
       while (enum.hasMoreElements()) {
         process(enum.nextElement());
       }
     }
     private static void process(Object obj) {
       JarEntry entry = (JarEntry)obj;
       String name = entry.getName();
       long size = entry.getSize();
       long compressedSize = entry.getCompressedSize();
       System.out.println(
           name + "\t" + size + "\t" + compressedSize);
     }
   }





Listing the Entries of a JAR File Manifest

    
import java.util.Iterator;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
public class Main {
  public static void main(String[] argv) throws Exception {
    JarFile jarfile = new JarFile("filename.jar");
    Manifest manifest = jarfile.getManifest();
    Map map = manifest.getEntries();
    for (Iterator it = map.keySet().iterator(); it.hasNext();) {
      String entryName = (String) it.next();
      Attributes attrs = (Attributes) map.get(entryName);
      for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext();) {
        Attributes.Name attrName = (Attributes.Name) it2.next();
        String attrValue = attrs.getValue(attrName);
      }
    }
  }
}





Listing the Main Attributes in a JAR File Manifest

    
import java.util.Iterator;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
public class Main {
  public static void main(String[] argv) throws Exception {
    JarFile jarfile = new JarFile("filename.jar");
    Manifest manifest = jarfile.getManifest();
    Attributes attrs = (Attributes) manifest.getMainAttributes();
    for (Iterator it = attrs.keySet().iterator(); it.hasNext();) {
      Attributes.Name attrName = (Attributes.Name) it.next();
      String attrValue = attrs.getValue(attrName);
    }
  }
}





Load an Icon from a jar

    
import javax.swing.Icon;
import javax.swing.UIManager;
public class Main {
  public static void main(String[] argv) throws Exception {
  }
  public static Icon getIconForType(int iconType) {
    switch (iconType) {
    case 0:
      return UIManager.getIcon("OptionPane.errorIcon");
    case 1:
      return UIManager.getIcon("OptionPane.informationIcon");
    case 2:
      return UIManager.getIcon("OptionPane.warningIcon");
    case 3:
      return UIManager.getIcon("OptionPane.questionIcon");
    }
    return null;
  }
}





Load an Image from a JAR file

    
import java.awt.Image;
import java.awt.Toolkit;
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    String imgName = "image.jpg";
    URL imgURL = Main.class.getResource(imgName);
    Toolkit tk = Toolkit.getDefaultToolkit();
    Image img = tk.getImage(imgURL);
  }
}





Load resource from Jar file

   
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public final class JarResources {
  Hashtable htSizes = new Hashtable();
  Hashtable htJarContents = new Hashtable();
  private String jarFileName;
  public JarResources(String jarFileName) throws Exception {
    this.jarFileName = jarFileName;
    ZipFile zf = new ZipFile(jarFileName);
    Enumeration e = zf.entries();
    while (e.hasMoreElements()) {
      ZipEntry ze = (ZipEntry) e.nextElement();

      htSizes.put(ze.getName(), new Integer((int) ze.getSize()));
    }
    zf.close();
    // extract resources and put them into the hashtable.
    FileInputStream fis = new FileInputStream(jarFileName);
    BufferedInputStream bis = new BufferedInputStream(fis);
    ZipInputStream zis = new ZipInputStream(bis);
    ZipEntry ze = null;
    while ((ze = zis.getNextEntry()) != null) {
      if (ze.isDirectory()) {
        continue;
      }

      int size = (int) ze.getSize();
      // -1 means unknown size.
      if (size == -1) {
        size = ((Integer) htSizes.get(ze.getName())).intValue();
      }
      byte[] b = new byte[(int) size];
      int rb = 0;
      int chunk = 0;
      while (((int) size - rb) > 0) {
        chunk = zis.read(b, rb, (int) size - rb);
        if (chunk == -1) {
          break;
        }
        rb += chunk;
      }
      htJarContents.put(ze.getName(), b);
    }
  }
  public byte[] getResource(String name) {
    return (byte[]) htJarContents.get(name);
  }
  private String dumpZipEntry(ZipEntry ze) {
    StringBuffer sb = new StringBuffer();
    if (ze.isDirectory()) {
      sb.append("d ");
    } else {
      sb.append("f ");
    }
    if (ze.getMethod() == ZipEntry.STORED) {
      sb.append("stored   ");
    } else {
      sb.append("defalted ");
    }
    sb.append(ze.getName());
    sb.append("\t");
    sb.append("" + ze.getSize());
    if (ze.getMethod() == ZipEntry.DEFLATED) {
      sb.append("/" + ze.getCompressedSize());
    }
    return (sb.toString());
  }
  public static void main(String[] args) throws Exception {
    JarResources jr = new JarResources("a.jar");
    byte[] buff = jr.getResource("b.gif");
  }
}





Make Temp Jar

 
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Main {
  static File makeTempJar(File moduleFile) throws IOException {
    String prefix = moduleFile.getName();
    if (prefix.endsWith(".jar") || prefix.endsWith(".JAR")) { // NOI18N
        prefix = prefix.substring(0, prefix.length() - 4);
    }
    if (prefix.length() < 3) prefix += ".";
    if (prefix.length() < 3) prefix += ".";
    if (prefix.length() < 3) prefix += ".";
    String suffix = "-test.jar"; // NOI18N
    File physicalModuleFile = File.createTempFile(prefix, suffix);
    physicalModuleFile.deleteOnExit();
    InputStream is = new FileInputStream(moduleFile);
    try {
        OutputStream os = new FileOutputStream(physicalModuleFile);
        try {
            byte[] buf = new byte[4096];
            int i;
            while ((i = is.read(buf)) != -1) {
                os.write(buf, 0, i);
            }
        } finally {
            os.close();
        }
    } finally {
        is.close();
    }
    return physicalModuleFile;
}

}





Manifest Writer

   
/*BEGIN_COPYRIGHT_BLOCK
 *
 * Copyright (c) 2001-2008, JavaPLT group at Rice University (drjava@rice.edu)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * 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.
 *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR
 * 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.
 *
 * This software is Open Source Initiative approved Open Source Software.
 * Open Source Initative Approved is a trademark of the Open Source Initiative.
 * 
 * This file is part of DrJava.  Download the current version of this project
 * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 * 
 * END_COPYRIGHT_BLOCK*/

import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.util.LinkedList;
import java.util.List;
import java.util.Iterator;
import java.io.*;
/** Writes manifest objects.  Useful for creating Manifest files without writing them to files. */
public class ManifestWriter {
  private List<String> _classPaths;
  private String _mainClass;
  private String _rawManifest;
  public static final Manifest DEFAULT = new ManifestWriter().getManifest();
  
  /** Create a new manifest file */
  public ManifestWriter() {
    _classPaths = new LinkedList<String>();
    _mainClass = null;
    _rawManifest = null;
  }
  
  /** Add a class path to the Manifest
    * @param path the path to be added
    */
  public void addClassPath(String path) {
    _classPaths.add(_classPaths.size(), path);
  }
  
  /** Set the main class of the Manifest
    * @param mainClass
    */
  public void setMainClass(String mainClass) {
    _mainClass = mainClass;
    _rawManifest = null;
  }
  
  public void setManifestContents(String rawManifest) {
    _rawManifest =  rawManifest;
    _mainClass = null;
  }
  
  /** Get an input stream to the contents of the manifest file
    * @return an InputStream whose contents are the contents of the Manifest file
    */
  protected InputStream getInputStream() {
    // NOTE: All significant lines in the manifest MUST end in the end of line character
    
    final StringBuilder sbuf = new StringBuilder();
    sbuf.append(Attributes.Name.MANIFEST_VERSION.toString());
    sbuf.append(": 1.0" + "\n");
    if( !_classPaths.isEmpty() ) {
      Iterator<String> iter = _classPaths.iterator();
      sbuf.append(Attributes.Name.CLASS_PATH.toString());
      sbuf.append(":");
      while (iter.hasNext()) {
        sbuf.append(" ");
        sbuf.append(iter.next());
      }
      sbuf.append("\n");
    }
    if( _mainClass != null ) {
      sbuf.append(Attributes.Name.MAIN_CLASS.toString());
      sbuf.append(": ");
      sbuf.append(_mainClass);
      sbuf.append("\n");
    }
    
    if(_rawManifest != null) {
      sbuf.append(_rawManifest); 
      
      if(!_rawManifest.endsWith("\n"))
        sbuf.append("\n");
    }
    
    try { return new ByteArrayInputStream(sbuf.toString().getBytes("UTF-8")); }
    catch (UnsupportedEncodingException e) { throw new RuntimeException(e); }
  }
  
  /** Get the Manifest object that this object created.
    * @return the Manifest that this builder created
    */
  public Manifest getManifest() {
    try {
      Manifest m = new Manifest();
      m.read(getInputStream());
      return m;
    }
    catch (IOException e) {
      e.printStackTrace();
      return null;
    }
  }
}





Reading a text file from a jar file without unzipping

    
   import java.io.*;
   import java.util.jar.*;
   public class JarRead {
     public static void main (String args[]) 
         throws IOException {
       if (args.length != 2) {
         System.out.println(
           "Please provide a JAR filename and file to read");
         System.exit(-1);
       }
       JarFile jarFile = new JarFile(args[0]);
       JarEntry entry = jarFile.getJarEntry(args[1]);
       InputStream input = jarFile.getInputStream(entry);
       process(input);
       jarFile.close();
     }
     private static void process(InputStream input) 
         throws IOException {
       InputStreamReader isr = 
      new InputStreamReader(input);
       BufferedReader reader = new BufferedReader(isr);
       String line;
       while ((line = reader.readLine()) != null) {
         System.out.println(line);
       }
       reader.close();
     }
   }





Retreive Binary File From Jar

   
/*
 * Copyright 2006 - 2008 Georges Stephan
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.util.logging.*;
import java.io.*;
/**
 * 
 * @author Georges Stephan
 */
public class Util {
  private static Logger logger = Logger.getLogger(Util.class.getName());
    
  public static String validateString(String aString) {
    if(aString==null) return("");
    
    aString=aString.replace("\"", " ");
    aString=aString.trim();
    return(aString);
  }
    
  public static String removeNonDigits(String aString) {
    StringBuffer newString = new StringBuffer();
    for(int x=0;x<aString.length();x++) {
      if(Character.isDigit(aString.charAt(x))) newString.append(aString.charAt(x));
    }
    return(newString.toString());
  }
    
  public static void createHome() throws Exception {
    File ch = new File(System.getProperty("user.home")+File.separator+".dataform");
    if(!ch.exists()) {
      if(!ch.mkdir()) throw new Exception("Failed to create the dataform configuration directory");
    }
  }
    
  public static String getHomeDir() {
    return(System.getProperty("user.home")+File.separator+".dataform"+File.separator);
  } 
    
  public static boolean retreiveTextFileFromJar(String resourceName,String targetDirectory) throws Exception {
    boolean found=false;
    if(resourceName!=null) {
      InputStream is = Util.class.getResourceAsStream(resourceName);
      if(is==null) logger.log(Level.WARNING,"The resource ""+resourceName+"" was not found.");
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      String line;
      String lineSep = System.getProperty("line.separator");
      StringBuffer sb = new StringBuffer();
      while ((line = br.readLine()) != null) {
        sb.append(line);
        sb.append(lineSep);
      }
      is.close();
      if(sb!=null) {
        if(sb.length()>0) {
          FileWriter temp = new FileWriter(targetDirectory+File.separator+resourceName);
          temp.write(sb.toString());
          temp.close();
          found=true;
        }
      }
    }
    return(found);    
  }
  
  public static boolean retreiveBinaryFileFromJar(String resourceName,String targetDirectory,Object resource) throws Exception {
    boolean found=false;
    if(resourceName!=null) {
      InputStream is = resource.getClass().getResourceAsStream(resourceName);
      if(is==null) throw new Exception ("Resource "+resourceName+" was not found.");
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      FileOutputStream fos = new FileOutputStream(targetDirectory+File.separator+resourceName.substring(resourceName.lastIndexOf("/"),resourceName.length()));
      byte[] buffer = new byte[1024];
            int bytesRead;
            
            while ((bytesRead = is.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            fos.flush();
            br.close();
            is.close();
      found=true;
    } else {
      found=false;
    }
    return found;
  }
}





Retreive Text File From Jar

   
/*
 * Copyright 2006 - 2008 Georges Stephan
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.util.logging.*;
import java.io.*;
/**
 * 
 * @author Georges Stephan
 */
public class Util {
  private static Logger logger = Logger.getLogger(Util.class.getName());
    
  public static String validateString(String aString) {
    if(aString==null) return("");
    
    aString=aString.replace("\"", " ");
    aString=aString.trim();
    return(aString);
  }
    
  public static String removeNonDigits(String aString) {
    StringBuffer newString = new StringBuffer();
    for(int x=0;x<aString.length();x++) {
      if(Character.isDigit(aString.charAt(x))) newString.append(aString.charAt(x));
    }
    return(newString.toString());
  }
    
  public static void createHome() throws Exception {
    File ch = new File(System.getProperty("user.home")+File.separator+".dataform");
    if(!ch.exists()) {
      if(!ch.mkdir()) throw new Exception("Failed to create the dataform configuration directory");
    }
  }
    
  public static String getHomeDir() {
    return(System.getProperty("user.home")+File.separator+".dataform"+File.separator);
  } 
    
  public static boolean retreiveTextFileFromJar(String resourceName,String targetDirectory) throws Exception {
    boolean found=false;
    if(resourceName!=null) {
      InputStream is = Util.class.getResourceAsStream(resourceName);
      if(is==null) logger.log(Level.WARNING,"The resource ""+resourceName+"" was not found.");
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      String line;
      String lineSep = System.getProperty("line.separator");
      StringBuffer sb = new StringBuffer();
      while ((line = br.readLine()) != null) {
        sb.append(line);
        sb.append(lineSep);
      }
      is.close();
      if(sb!=null) {
        if(sb.length()>0) {
          FileWriter temp = new FileWriter(targetDirectory+File.separator+resourceName);
          temp.write(sb.toString());
          temp.close();
          found=true;
        }
      }
    }
    return(found);    
  }
  
  public static boolean retreiveBinaryFileFromJar(String resourceName,String targetDirectory,Object resource) throws Exception {
    boolean found=false;
    if(resourceName!=null) {
      InputStream is = resource.getClass().getResourceAsStream(resourceName);
      if(is==null) throw new Exception ("Resource "+resourceName+" was not found.");
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      FileOutputStream fos = new FileOutputStream(targetDirectory+File.separator+resourceName.substring(resourceName.lastIndexOf("/"),resourceName.length()));
      byte[] buffer = new byte[1024];
            int bytesRead;
            
            while ((bytesRead = is.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            fos.flush();
            br.close();
            is.close();
      found=true;
    } else {
      found=false;
    }
    return found;
  }
}





Retrieves the manifest from a JAR file and writes the manifest contents to a file.

    
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
public class Main {
  public static void main(String[] argv) throws Exception {
    JarFile jarfile = new JarFile("filename.jar");
    Manifest manifest = jarfile.getManifest();
    OutputStream fos = new FileOutputStream("manifest");
    jarfile.getManifest().write(fos);
    fos.close();
  }
}





Search all jar and zip files in the current directory for a given class file

   
/* 
 * The QueryForm License, Version 1.1
 *
 * Copyright (c) 1998 - 2003 David F. Glasser.  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 acknowledgment:
 *       "This product includes software developed by 
 *        David F. Glasser."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "QueryForm" and "David F. Glasser" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact dglasser@pobox.ru.
 *
 * 5. Products derived from this software may not be called "QueryForm",
 *    nor may "QueryForm" appear in their name, without prior written
 *    permission of David F. Glasser.
 *
 * 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 DAVID F. GLASSER, THE APACHE SOFTWARE 
 * FOUNDATION OR ITS CONTRIBUTORS, OR ANY AUTHORS OR DISTRIBUTORS
 * OF THIS SOFTWARE 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.
 * 
 *
 * This product includes software developed by the
 * Apache Software Foundation (http://www.apache.org/).
 *
 * 
 *
 * $Source: /cvsroot/qform/qform/src/org/glasser/util/JarSearcher.java,v $
 * $Revision: 1.1 $
 * $Author: dglasser $
 * $Date: 2003/01/25 23:17:02 $
 * 
 * --------------------------------------------------------------------
 */
import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.io.*;
/**
 * This program will search all jar and zip files in the current directory for
 * a given class file.
 * 
 * @author Dave Glasser
 */
public class JarSearcher {
    /**
     * Returns true if the jar or zip file at jarFilePath contains (with the internal
     * path) the file named by classFilePath. 
     */
    public static boolean searchJarFile(String jarFilePath, String classFilePath) {
        return searchJarFile( new File(jarFilePath), classFilePath);
    }
    public static boolean searchJarFile(File file, String classFilePath) {
        try {
            if(!file.exists()) return false;
    
            ZipFile jarFile = new ZipFile(file);
            if(jarFile.getEntry(classFilePath) != null) {
                jarFile.close();
                return true;
            }
            else {
                jarFile.close();
                return false;
            }
        }
        catch(IOException ex) {
            System.out.println(ex.toString());
            return false;
        }
    }


  static class ArchiveFilter implements FileFilter {
    public boolean accept(File pathName) {
      String upcase = pathName.getName().toUpperCase();
      if(upcase.endsWith(".ZIP") || upcase.endsWith(".JAR")) return true;
      return false;
    }
  }

    public static void main (String[] args)  {
        if(args.length == 0) {
            System.out.println("usage: java ClassFinder <class name>\n\n"
                               + "example: java ClassFinder java.lang.String\n");
            System.exit(0);
        }
        File cwd = new File(".");
        File[] archives = cwd.listFiles(new ArchiveFilter());
    
        String classFileName = args[0].replace(".", "/");
        if(classFileName.endsWith(".class") == false) {
            classFileName += ".class";
        }
    
        System.out.println("Searching for " + classFileName + " ...");
        for(int j=0; j<archives.length; j++) {
    //      System.out.println("Searching " + archives[j].getName());
          if(searchJarFile(archives[j], classFileName)) {
            System.out.println("FOUND IN " + archives[j].getName());
          }
        }
    }
}





Search class in class path and Jar files

 
/*
 * $Id: ClassSearchUtils.java,v 1.1 2009/03/01 12:01:11 rah003 Exp $
 *
 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
import java.awt.HeadlessException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;
public class ClassSearchUtils {
    private static final Logger log = Logger.getAnonymousLogger();
    /**
     * Classloader to be used to obtain resources from file system.
     */
    private ClassLoader classloader;
    /**
     * List of the resource found in the classpath.
     */
    private ArrayList list;
    /**
     * Extension of the resource to be found in the classpath.
     */
    private String extension;
    private String prefix;
    /**
     * Search for the resource with the extension in the classpath. Method
     * self-instantiate factory for every call to ensure thread safety.
     * @param extension Mandatory extension of the resource. If all resources
     * are required extension should be empty string. Null extension is not
     * allowed and will cause method to fail.
     * @return List of all resources with specified extension.
     */
    public static List<Class<?>> searchClassPath(String prefix) {
        return searchClassPath(prefix, ".class");
    }
    /**
     * Search for the resource with the extension in the classpath. Method
     * self-instantiate factory for every call to ensure thread safety.
     * @param extension Mandatory extension of the resource. If all resources
     * are required extension should be empty string. Null extension is not
     * allowed and will cause method to fail.
     * @return List of all resources with specified extension.
     */
    public static List searchClassPath(String prefix, String extension) {
        ClassSearchUtils factory = new ClassSearchUtils();
        factory.prefix = prefix;
        return factory.find(extension);
    }
    /**
     * Search for the resource with the extension in the classpath.
     * @param extension Mandatory extension of the resource. If all resources
     * are required extension should be empty string. Null extension is not
     * allowed and will cause method to fail.
     * @return List of all resources with specified extension.
     */
    private List<Class<?>> find(String extension) {
        this.extension = extension;
        this.list = new ArrayList();
        this.classloader = this.getClass().getClassLoader();
        String classpath = System.getProperty("java.class.path");
        try {
            Method method =
                this.classloader.getClass().getMethod("getClassPath", (Class<?>) null);
            if (method != null) {
                classpath = (String) method.invoke(this.classloader, (Object) null);
            }
        } catch (Exception e) {
            // ignore
        }
        if (classpath == null) {
            classpath = System.getProperty("java.class.path");
        }
        StringTokenizer tokenizer =
            new StringTokenizer(classpath, File.pathSeparator);
        String token;
        File dir;
        String name;
        while (tokenizer.hasMoreTokens()) {
            token = tokenizer.nextToken();
            dir = new File(token);
            if (dir.isDirectory()) {
                lookInDirectory("", dir);
            }
            if (dir.isFile()) {
                name = dir.getName().toLowerCase();
                if (name.endsWith(".zip") || name.endsWith(".jar")) {
                    this.lookInArchive(dir);
                }
            }
        }
        return this.list;
    }
    /**
     * @param name Name of to parent directories in java class notation (dot
     * separator)
     * @param dir Directory to be searched for classes.
     */
    private void lookInDirectory(String name, File dir) {
        log.fine( "Looking in directory [" + dir.getName() + "].");
        File[] files = dir.listFiles();
        File file;
        String fileName;
        final int size = files.length;
        for (int i = 0; i < size; i++) {
            file = files[i];
            fileName = file.getName();
            if (file.isFile()
                && fileName.toLowerCase().endsWith(this.extension)) {
                try {
                    if (this.extension.equalsIgnoreCase(".class")) {
                        fileName = fileName.substring(0, fileName.length() - 6);
                        // filter ignored resources
                        if (!(name + fileName).startsWith(this.prefix)) {
                            continue;
                        }
                        log.fine(
                            "Found class: [" + name + fileName + "].");
                        this.list.add(Class.forName(name + fileName));
                    } else {
                        this.list.add(
                            this.classloader.getResource(
                                name.replace(".", File.separatorChar)
                                    + fileName));
                    }
                } catch (ClassNotFoundException e) {
                    // ignore
                } catch (NoClassDefFoundError e) {
                        //ignore too
                } catch (ExceptionInInitializerError e) {
                    if (e.getCause() instanceof HeadlessException) {
                        // running in headless env ... ignore 
                    } else {
                        throw e;
                    }
                }
            }
            // search recursively.
            // I don"t like that but we will see how it will work.
            if (file.isDirectory()) {
                lookInDirectory(name + fileName + ".", file);
            }
        }
    }
    /**
     * Search archive files for required resource.
     * @param archive Jar or zip to be searched for classes or other resources.
     */
    private void lookInArchive(File archive) {
        log.fine(
            "Looking in archive ["
                + archive.getName()
                + "] for extension ["
                + this.extension
                + "].");
        JarFile jarFile = null;
        try {
            jarFile = new JarFile(archive);
        } catch (IOException e) {
            log.warning(
                "Non fatal error. Unable to read jar item.");
            return;
        }
        Enumeration entries = jarFile.entries();
        JarEntry entry;
        String entryName;
        while (entries.hasMoreElements()) {
            entry = (JarEntry) entries.nextElement();
            entryName = entry.getName();
            if (entryName.toLowerCase().endsWith(this.extension)) {
                try {
                    if (this.extension.equalsIgnoreCase(".class")) {
                        // convert name into java classloader notation
                        entryName =
                            entryName.substring(0, entryName.length() - 6);
                        entryName = entryName.replace("/", ".");
                        // filter ignored resources
                        if (!entryName.startsWith(this.prefix)) {
                            continue;
                        }
                        log.fine(
                            "Found class: [" + entryName + "]. ");
                        this.list.add(Class.forName(entryName));
                    } else {
                        this.list.add(this.classloader.getResource(entryName));
                        log.fine(
                            "Found appropriate resource with name ["
                                + entryName
                                + "]. Resource instance:"
                                + this.classloader.getResource(entryName));
                    }
                } catch (Throwable e) {
                    // ignore
                    log.warning(
                        "Unable to load resource ["
                            + entryName
                            + "] form file ["
                            + archive.getAbsolutePath()
                            + "].");
                }
            }
        }
    }
}





Sign jar with the certificate named alias in the keystore

    
jarsigner -keystore .keystore -storepass password myjar.jar alias





Some utility classes for manipulating JAR files

   
/* 
 * 
 * 
 * Copyright 2005 Vincent Massol.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * 
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
/**
 * Some utility classes for manipulating JAR files.
 * 
 * @version $Id $
 */
public final class JarUtils
{   
    /**
     * Create a jar file from a particular directory.
     * 
     * @param root in the root directory
     * @param directory in the directory we are adding
     * @param jarStream the jar stream to be added to
     * @throws IOException on IOException
     */
    protected void createJarFromDirectory(File root,
                                          File directory,
                                          JarOutputStream jarStream)
        throws IOException
    {
        byte[] buffer = new byte[40960];
        int bytesRead;
        File[] filesToAdd = directory.listFiles();
        for (int i = 0; i < filesToAdd.length; i++)
        {
            File fileToAdd = filesToAdd[i];
            if (fileToAdd.isDirectory())
            {
                createJarFromDirectory(root, fileToAdd, jarStream);
            }
            else
            {
                FileInputStream addFile = new FileInputStream(fileToAdd);
                try
                {
                    // Create a jar entry and add it to the temp jar.
                    String entryName = fileToAdd.getPath().substring(root.getPath().length() + 1);
                    
                    // If we leave these entries as "\"s, then the resulting zip file won"t be
                    // expandable on Unix operating systems like OSX, because it is possible to 
                    // have filenames with \s in them - so it"s impossible to determine that this 
                    // is actually a directory.
                    entryName = entryName.replace("\\", "/");
                    JarEntry entry = new JarEntry(entryName);
                    jarStream.putNextEntry(entry);
                    // Read the file and write it to the jar.
                    while ((bytesRead = addFile.read(buffer)) != -1)
                    {
                        jarStream.write(buffer, 0, bytesRead);
                    }
                    jarStream.closeEntry();
                }
                finally
                {
                    addFile.close();
                }
            }
        }
    }
    /**
     * Create a JAR file from a directory, recursing through children.
     * 
     * @param directory in directory source
     * @param outputJar in file to output the jar data to
     * @return out File that was generated
     * @throws IOException when there is an I/O exception
     */
    public File createJarFromDirectory(String directory, File outputJar)
        throws IOException
    {
        JarOutputStream jarStream = null;
        try
        {
            if (!outputJar.getParentFile().exists())
            {
                outputJar.getParentFile().mkdirs();
            }
            jarStream = new JarOutputStream(new FileOutputStream(outputJar));
            File dir = new File(directory);
            createJarFromDirectory(dir, dir, jarStream);
        }
        finally
        {
            if (jarStream != null)
            {
                jarStream.close();
            }
        }
        return outputJar;
    }
}





Unjar a file

 
/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
/** A utility class for dealing with Jar files.
@author Scott.Stark@jboss.org
@version $Revision: 2787 $
*/
public final class JarUtils
{
   /**
    * Hide the constructor
    */
   private JarUtils()
   {
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, new File[] { src }, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File src) throws IOException
   {
      jar(out, new File[] { src }, null, null, null);
   }
 
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src) throws IOException
   {
      jar(out, src, null, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, filter, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter)
      throws IOException
   {
      jar(out, src, filter, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @param prefix The name of an arbitrary directory that will precede all
    *        entries in the jar archive.  If null, then no prefix will be
    *        used.
    * @param man The manifest to use for the Jar archive.  If null, then no
    *        manifest will be included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter,
      String prefix, Manifest man) throws IOException
   {
      
      for (int i = 0; i < src.length; i++)
      {
         if (!src[i].exists())
         {
            throw new FileNotFoundException(src.toString());
         }
      }
      
      JarOutputStream jout;
      if (man == null)
      {
         jout = new JarOutputStream(out);
      }
      else
      {
         jout = new JarOutputStream(out, man);
      }
      if (prefix != null && prefix.length() > 0 && !prefix.equals("/"))
      {
         // strip leading "/"
         if (prefix.charAt(0) == "/")
         {
            prefix = prefix.substring(1);
         }
         // ensure trailing "/"
         if (prefix.charAt(prefix.length() - 1) != "/")
         {
            prefix = prefix + "/";
         }
      } 
      else
      {
         prefix = "";
      }
      JarInfo info = new JarInfo(jout, filter);
      for (int i = 0; i < src.length; i++)
      {
         jar(src[i], prefix, info);
      }
      jout.close();
   }
   
   /**
    * This simple convenience class is used by the jar method to reduce the
    * number of arguments needed.  It holds all non-changing attributes
    * needed for the recursive jar method.
    */
   private static class JarInfo
   {
      public JarOutputStream out;
      public FileFilter filter;
      public byte[] buffer;
      
      public JarInfo(JarOutputStream out, FileFilter filter)
      {
         this.out = out;
         this.filter = filter;
         buffer = new byte[1024];
      }
   }
   
   /**
    * This recursive method writes all matching files and directories to
    * the jar output stream.
    */
   private static void jar(File src, String prefix, JarInfo info)
      throws IOException
   {
      
      JarOutputStream jout = info.out;
      if (src.isDirectory())
      {
         // create / init the zip entry
         prefix = prefix + src.getName() + "/";
         ZipEntry entry = new ZipEntry(prefix);
         entry.setTime(src.lastModified());
         entry.setMethod(JarOutputStream.STORED);
         entry.setSize(0L);
         entry.setCrc(0L);
         jout.putNextEntry(entry);
         jout.closeEntry();
         
         // process the sub-directories
         File[] files = src.listFiles(info.filter);
         for (int i = 0; i < files.length; i++)
         {
            jar(files[i], prefix, info);
         }
      } 
      else if (src.isFile())
      {
         // get the required info objects
         byte[] buffer = info.buffer;
         
         // create / init the zip entry
         ZipEntry entry = new ZipEntry(prefix + src.getName());
         entry.setTime(src.lastModified());
         jout.putNextEntry(entry);
         
         // dump the file
         FileInputStream in = new FileInputStream(src);
         int len;
         while ((len = in.read(buffer, 0, buffer.length)) != -1)
         {
            jout.write(buffer, 0, len);
         }
         in.close();
         jout.closeEntry();
      }
   }
   
   public static void unjar(InputStream in, File dest) throws IOException
   {
      if (!dest.exists())
      {
         dest.mkdirs();
      }
      if (!dest.isDirectory())
      {
         throw new IOException("Destination must be a directory.");
      }
      JarInputStream jin = new JarInputStream(in);
      byte[] buffer = new byte[1024];
      
      ZipEntry entry = jin.getNextEntry();
      while (entry != null)
      {
         String fileName = entry.getName();
         if (fileName.charAt(fileName.length() - 1) == "/")
         {
            fileName = fileName.substring(0, fileName.length() - 1);
         }
         if (fileName.charAt(0) == "/")
         {
            fileName = fileName.substring(1);
         }
         if (File.separatorChar != "/")
         {
            fileName = fileName.replace("/", File.separatorChar);
         }
         File file = new File(dest, fileName);
         if (entry.isDirectory())
         {
            // make sure the directory exists
            file.mkdirs();
            jin.closeEntry();
         } 
         else
         {
            // make sure the directory exists
            File parent = file.getParentFile();
            if (parent != null && !parent.exists())
            {
               parent.mkdirs();
            }
            
            // dump the file
            OutputStream out = new FileOutputStream(file);
            int len = 0;
            while ((len = jin.read(buffer, 0, buffer.length)) != -1)
            {
               out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
            jin.closeEntry();
            file.setLastModified(entry.getTime());
         }
         entry = jin.getNextEntry();
      }
      /* Explicity write out the META-INF/MANIFEST.MF so that any headers such
      as the Class-Path are see for the unpackaged jar
      */
      Manifest mf = jin.getManifest();
      if (mf != null)
      {
         File file = new File(dest, "META-INF/MANIFEST.MF");
         File parent = file.getParentFile();
         if( parent.exists() == false )
         {
            parent.mkdirs();
         }
         OutputStream out = new FileOutputStream(file);
         mf.write(out);
         out.flush();
         out.close();
      }
      jin.close();
   }
   /** Given a URL check if its a jar url(jar:<url>!/archive) and if it is,
    extract the archive entry into the given dest directory and return a file
    URL to its location. If jarURL is not a jar url then it is simply returned
    as the URL for the jar.
    @param jarURL the URL to validate and extract the referenced entry if its
      a jar protocol URL
    @param dest the directory into which the nested jar will be extracted.
    @return the file: URL for the jar referenced by the jarURL parameter.
    * @throws IOException 
    */
   public static URL extractNestedJar(URL jarURL, File dest)
      throws IOException
   {
      // This may not be a jar URL so validate the protocol 
      if( jarURL.getProtocol().equals("jar") == false )
         return jarURL;
      String destPath = dest.getAbsolutePath();
      URLConnection urlConn = jarURL.openConnection();
      JarURLConnection jarConn = (JarURLConnection) urlConn;
      // Extract the archive to dest/jarName-contents/archive
      String parentArchiveName = jarConn.getJarFile().getName();
      // Find the longest common prefix between destPath and parentArchiveName
      int length = Math.min(destPath.length(), parentArchiveName.length());
      int n = 0;
      while( n < length )
      {
         char a = destPath.charAt(n);
         char b = parentArchiveName.charAt(n);
         if( a != b )
            break;
         n ++;
      }
      // Remove any common prefix from parentArchiveName
      parentArchiveName = parentArchiveName.substring(n);
      File archiveDir = new File(dest, parentArchiveName+"-contents");
      if( archiveDir.exists() == false && archiveDir.mkdirs() == false )
         throw new IOException("Failed to create contents directory for archive, path="+archiveDir.getAbsolutePath());
      String archiveName = jarConn.getEntryName();
      File archiveFile = new File(archiveDir, archiveName);
      File archiveParentDir = archiveFile.getParentFile();
      if( archiveParentDir.exists() == false && archiveParentDir.mkdirs() == false )
         throw new IOException("Failed to create parent directory for archive, path="+archiveParentDir.getAbsolutePath());
      InputStream archiveIS = jarConn.getInputStream();
      FileOutputStream fos = new FileOutputStream(archiveFile);
      BufferedOutputStream bos = new BufferedOutputStream(fos);
      byte[] buffer = new byte[4096];
      int read;
      while( (read = archiveIS.read(buffer)) > 0 )
      {
         bos.write(buffer, 0, read);
      }
      archiveIS.close();
      bos.close();
      // Return the file url to the extracted jar
      return archiveFile.toURL();
   }

   public static void main(String[] args) throws Exception
   {
      if (args.length == 0)
      {
         System.out.println("usage: <x or c> <jar-archive> <files...>");
         System.exit(0);
      }
      if (args[0].equals("x"))
      {
         BufferedInputStream in = new BufferedInputStream(new FileInputStream(args[1]));
         File dest = new File(args[2]);
         unjar(in, dest);
      }
      else if (args[0].equals("c"))
      {
         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(args[1]));
         File[] src = new File[args.length - 2];
         for (int i = 0; i < src.length; i++)
         {
            src[i] = new File(args[2 + i]);
         }
         jar(out, src);
      }
      else
      {
         System.out.println("Need x or c as first argument");
      }
   }
}





When no entry is specified on the URL, the entry name is null

    
import java.net.JarURLConnection;
import java.net.URL;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("jar:file:/c://my.jar!/");
    JarURLConnection conn = (JarURLConnection) url.openConnection();
    String entryName = conn.getEntryName(); // null
  }
}





Zip jar Imploder

  
/*******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * @author Barry Feigenbaum
 */
public class ZipImploder {
  protected int dirCount, fileCount;
  /**
   * @return Returns the dirCount.
   */
  public int getDirCount() {
    return dirCount;
  }
  /**
   * @return Returns the fileCount.
   */
  public int getFileCount() {
    return fileCount;
  }
  /**
   * create a new imploder with no verbosity
   * 
   */
  public ZipImploder() {
    this(false);
  }
  /**
   * create a new imploder with the specified verbosity state
   * 
   * @param verbose -
   *          verbosity state
   */
  public ZipImploder(boolean verbose) {
    setVerbose(verbose);
  }
  protected boolean verbose;
  /**
   * get the verbose mode
   * 
   * @return verbosity mode
   */
  public boolean getVerbose() {
    return verbose;
  }
  /**
   * set the verbosity mode
   * 
   * @param f
   *          verbosity state
   */
  public void setVerbose(boolean f) {
    verbose = f;
  }
  protected String baseDir;
  /**
   * @return Returns the baseDir.
   */
  public String getBaseDir() {
    return baseDir;
  }
  /**
   * @param baseDir
   *          The baseDir to set.
   * @throws IOException
   */
  public void setBaseDir(String baseDir) throws IOException {
    if (baseDir != null) {
      baseDir = new File(baseDir).getCanonicalPath();
      baseDir = baseDir.replace("\\", "/");
    }
    this.baseDir = baseDir;
  }
  protected Manifest manifest;
  /**
   * @return Returns the manifest
   */
  public Manifest getManifest() {
    return manifest;
  }
  /**
   * @param manifest
   *          The manifest to set.
   */
  public void setManifest(Manifest manifest) {
    this.manifest = manifest;
  }
  protected boolean includeDirs;
  /**
   * returns whether or not path information is included in .zip
   * 
   * @return <code>true</code> if path information is included,
   *         <code>false</code> otherwise
   */
  public boolean getIncludeDirs() {
    return includeDirs;
  }
  /**
   * set whether or not path information is included in .zip files
   * 
   * @param includeDirs
   *          include path inforamtion in .zip file
   */
  public void setIncludeDirs(boolean includeDirs) {
    this.includeDirs = includeDirs;
  }
  /**
   * implode source directory into .jar/.zip file
   * 
   * @param zipName
   *          name of target file
   * @param jarName
   *          name of target file
   * @param sourceDir
   *          source directory name
   * @exception IOException
   *              error creating a target file
   */
  public void process(String zipName, String jarName, String sourceDir) throws IOException {
    dirCount = 0;
    fileCount = 0;
    if (zipName != null) {
      processZip(zipName, sourceDir);
    }
    if (jarName != null) {
      processJar(jarName, sourceDir);
    }
  }
  /**
   * Implode target JAR file from a source directory
   * 
   * @param jarName
   *          name of target file
   * @param sourceDir
   *          source directory name
   * @exception IOException
   *              error creating a target file
   */
  public void processJar(String jarName, String sourceDir) throws IOException {
    processJar(jarName, sourceDir, null);
  }
  /**
   * Implode target JAR file from a source directory
   * 
   * @param jarName
   *          name of target file
   * @param sourceDir
   *          source directory name (
   * @param comment
   * @exception IOException
   *              error creating a target file
   */
  public void processJar(String jarName, String sourceDir, String comment) throws IOException {
    processJar(jarName, sourceDir, comment, -1, -1);
  }
  /**
   * Implode target JAR file from a source directory
   * 
   * @param jarName -
   *          name of target .jar
   * @param sourceDir -
   *          source directory
   * @param comment -
   *          comment for .jar file
   * @param method
   * @param level
   * @throws IOException
   */
  public void processJar(String jarName, String sourceDir, String comment, int method, int level)
      throws IOException {
    String dest = setup(jarName, sourceDir);
    Manifest man = getManifest();
    JarOutputStream jos = man != null ? new JarOutputStream(new BufferedOutputStream(
        new FileOutputStream(dest)), man) : new JarOutputStream(new BufferedOutputStream(
        new FileOutputStream(dest)));
    configure(jos, comment, method, level);
    process(jos, new File(sourceDir));
  }
  /**
   * Implode target JAR file from a source directory
   * 
   * @param zipName
   *          name of target file
   * @param sourceDir
   *          source directory name (
   * @exception IOException
   *              error creating a target file
   */
  public void processZip(String zipName, String sourceDir) throws IOException {
    processZip(zipName, sourceDir, null);
  }
  /**
   * Implode target zip file from a source directory
   * 
   * @param zipName
   * @param sourceDir
   * @param comment
   * @throws IOException
   */
  public void processZip(String zipName, String sourceDir, String comment) throws IOException {
    processZip(zipName, sourceDir, comment, -1, -1);
  }
  /**
   * Implode target zip file from a source directory
   * 
   * @param zipName
   * @param sourceDir
   * @param comment
   * @param method
   * @param level
   * @throws IOException
   */
  public void processZip(String zipName, String sourceDir, String comment, int method, int level)
      throws IOException {
    String dest = setup(zipName, sourceDir);
    ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
    configure(zos, comment, method, level);
    process(zos, new File(sourceDir));
  }
  protected void configure(ZipOutputStream zos, String comment, int method, int level) {
    if (comment != null) {
      zos.setComment(comment);
    }
    if (method >= 0) {
      zos.setMethod(method);
    }
    if (level >= 0) {
      zos.setLevel(level);
    }
  }
  protected String setup(String zipName, String sourceDir) throws IOException {
    File dir = new File(sourceDir);
    if (!dir.exists() && !dir.isDirectory()) {
      throw new IOException("source must exist and be a directory: " + dir);
    }
    String source = dir.getCanonicalPath();
    String dest = new File(zipName).getCanonicalPath();
    return dest;
  }
  protected void process(ZipOutputStream zos, File dir) throws IOException {
    try {
      processDir(zos, dir);
    } finally {
      zos.close();
    }
  }
  protected String removeDrive(String path) {
    return path.length() >= 2 && path.charAt(1) == ":" ? path.substring(2) : path;
  }
  protected String removeLead(String path) {
    if (baseDir != null && path.startsWith(baseDir)) {
      path = path.substring(baseDir.length());
      if (path.length() >= 1) {
        if (path.charAt(0) == "/" || path.charAt(0) == "\\") {
          path = path.substring(1); // drop leading /
        }
      }
    }
    return path;
  }
  public void processDir(ZipOutputStream zos, File dir) throws IOException {
    String path = dir.getCanonicalPath();
    path = path.replace("\\", "/");
    if (includeDirs) {
      if (baseDir == null || path.length() > baseDir.length()) {
        String xpath = removeDrive(removeLead(path));
        if (xpath.length() > 0) {
          xpath += "/";
          ZipEntry ze = new ZipEntry(xpath);
          zos.putNextEntry(ze);
        }
      }
    }
    dirCount++;
    String[] files = dir.list();
    for (int i = 0; i < files.length; i++) {
      String file = files[i];
      File f = new File(dir, file);
      if (f.isDirectory()) {
        processDir(zos, f);
      } else {
        processFile(zos, f);
      }
    }
  }
  /**
   * process a single file for a .zip file
   * 
   * @param zos
   * @param f
   * @throws IOException
   */
  public void processFile(ZipOutputStream zos, File f) throws IOException {
    String path = f.getCanonicalPath();
    path = path.replace("\\", "/");
    String xpath = removeDrive(removeLead(path));
    ZipEntry ze = new ZipEntry(xpath);
    ze.setTime(f.lastModified());
    ze.setSize(f.length());
    zos.putNextEntry(ze);
    fileCount++;
    try {
      copyFileEntry(zos, f);
    } finally {
      zos.closeEntry();
    }
  }
  protected void copyFileEntry(ZipOutputStream zos, File f) throws IOException {
    DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(f)));
    try {
      copyFileEntry(zos, dis);
    } finally {
      try {
        dis.close();
      } catch (IOException ioe) {
      }
    }
  }
  protected void copyFileEntry(ZipOutputStream zos, DataInputStream dis) throws IOException {
    byte[] bytes = readAllBytes(dis);
    zos.write(bytes, 0, bytes.length);
  }
  // *** below may be slow for large files ***
  /** Read all the bytes in a stream */
  protected byte[] readAllBytes(DataInputStream is) throws IOException {
    byte[] bytes = new byte[0];
    for (int len = is.available(); len > 0; len = is.available()) {
      byte[] xbytes = new byte[len];
      int count = is.read(xbytes);
      if (count > 0) {
        byte[] nbytes = new byte[bytes.length + count];
        System.arraycopy(bytes, 0, nbytes, 0, bytes.length);
        System.arraycopy(xbytes, 0, nbytes, bytes.length, count);
        bytes = nbytes;
      }
    }
    return bytes;
  }
  protected void print(String s) {
    System.out.print(s);
  }
  /** Print command help text. */
  public static void printHelp() {
    System.out.println();
    System.out.println("Usage: java " + ZipImploder.class.getName());
    System.out.println("       (-jar <jarName> {-manifest <manfile>} | -zip <zipName>)");
    System.out.println("       -dir <sourceDir> {-lead <leadDir>} {-doDirs} {-verbose}");
    System.out.println("Where:");
    System.out.println("  <jarName>     path to target jar");
    System.out.println("  <zipName>     path to target zip");
    System.out.println("  <manfile>     path to manifest file");
    System.out.println("  <sourceDir>   path to source directory; must exist");
    System.out
        .println("  <leadDir>     partial lead path to remove from stored entries; default: <sourceDir>");
    System.out.println("  <noDirs>      skip output of directory entries");
    System.out.println("  <verbose>     output progress information");
    System.out.println("Note: switch case or order is not important");
  }
  protected static void reportError(String msg) {
    System.err.println(msg);
    // printHelp();
    System.exit(1);
  }
  /**
   * Main command line entry point.
   * 
   * @param args
   */
  public static void main(final String[] args) {
    if (args.length == 0) {
      printHelp();
      System.exit(0);
    }
    String zipName = null;
    String jarName = null;
    String manName = null;
    String sourceDir = null;
    String leadDir = null;
    boolean jarActive = false, manActive = false, zipActive = false, sourceDirActive = false, leadDirActive = false;
    boolean verbose = false;
    boolean noDirs = false;
    // process arguments
    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.charAt(0) == "-") { // switch
        arg = arg.substring(1);
        if (arg.equalsIgnoreCase("jar")) {
          jarActive = true;
          manActive = false;
          zipActive = false;
          sourceDirActive = false;
          leadDirActive = false;
        } else if (arg.equalsIgnoreCase("manifest")) {
          jarActive = false;
          manActive = true;
          zipActive = false;
          sourceDirActive = false;
          leadDirActive = false;
        } else if (arg.equalsIgnoreCase("zip")) {
          zipActive = true;
          manActive = false;
          jarActive = false;
          sourceDirActive = false;
          leadDirActive = false;
        } else if (arg.equalsIgnoreCase("dir")) {
          jarActive = false;
          manActive = false;
          zipActive = false;
          sourceDirActive = true;
          leadDirActive = false;
        } else if (arg.equalsIgnoreCase("lead")) {
          jarActive = false;
          manActive = false;
          zipActive = false;
          sourceDirActive = false;
          leadDirActive = true;
        } else if (arg.equalsIgnoreCase("noDirs")) {
          noDirs = true;
          jarActive = false;
          manActive = false;
          zipActive = false;
          sourceDirActive = false;
          leadDirActive = false;
        } else if (arg.equalsIgnoreCase("verbose")) {
          verbose = true;
          jarActive = false;
          manActive = false;
          zipActive = false;
          sourceDirActive = false;
          leadDirActive = false;
        } else {
          reportError("Invalid switch - " + arg);
        }
      } else {
        if (jarActive) {
          if (jarName != null) {
            reportError("Duplicate value - " + arg);
          }
          jarName = arg;
        } else if (manActive) {
          if (manName != null) {
            reportError("Duplicate value - " + arg);
          }
          manName = arg;
        } else if (zipActive) {
          if (zipName != null) {
            reportError("Duplicate value - " + arg);
          }
          zipName = arg;
        } else if (sourceDirActive) {
          if (sourceDir != null) {
            reportError("Duplicate value - " + arg);
          }
          sourceDir = arg;
        } else if (leadDirActive) {
          if (leadDir != null) {
            reportError("Duplicate value - " + arg);
          }
          leadDir = arg;
        } else {
          reportError("Too many parameters - " + arg);
        }
      }
    }
    if (sourceDir == null || (zipName == null && jarName == null)) {
      reportError("Missing parameters");
    }
    if (manName != null && zipName != null) {
      reportError("Manifests not supported on ZIP files");
    }
    if (leadDir == null) {
      leadDir = new File(sourceDir).getAbsolutePath().replace("\\", "/") + "/";
    }
    if (verbose) {
      System.out.println("Effective command: "
          + ZipImploder.class.getName()
          + (jarName != null ? " -jar " + jarName
              + (manName != null ? " -manifest " + manName : "") : "")
          + (zipName != null ? " -zip " + zipName : "") + " -dir " + sourceDir + " -lead "
          + leadDir + (noDirs ? " -noDirs" : "") + (verbose ? " -verbose" : ""));
    }
    try {
      ZipImploder zi = new ZipImploder(verbose);
      if (leadDir != null) {
        zi.setBaseDir(leadDir);
      }
      if (manName != null) {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(manName));
        try {
          zi.setManifest(new Manifest(bis));
        } finally {
          bis.close();
        }
      }
      zi.setIncludeDirs(!noDirs);
      zi.process(zipName, jarName, sourceDir);
      if (verbose) {
        System.out
            .println("\nDone Directories=" + zi.getDirCount() + " Files=" + zi.getFileCount());
      }
    } catch (IOException ioe) {
      System.err.println("Exception - " + ioe.getMessage());
      // ioe.printStackTrace(); // *** debug ***
      System.exit(2);
    }
  }
}