Java tutorial
/* * 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.com bug parade, see: // http://developer.java.sun.com/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(); } } }