001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.core.util.jar;
019:
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.util.ArrayList;
024: import java.util.Enumeration;
025: import java.util.List;
026: import java.util.StringTokenizer;
027: import java.util.jar.JarEntry;
028: import java.util.jar.JarFile;
029: import java.util.jar.Manifest;
030: import java.util.zip.ZipEntry;
031:
032: import org.sape.carbon.core.exception.ExceptionUtility;
033: import org.sape.carbon.core.exception.InvalidParameterException;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037:
038: /**
039: * This class enhances functionality of java.util.jar.JarFile.
040: * Additional functionality includes jar entry removal, the ability to list
041: * the entries within a directory within the jar, and the ability to get
042: * an output stream for modifying extisting entries.
043: *
044: * @see java.util.jar.JarFile
045: *
046: * Copyright 2002 Sapient
047: * @since carbon 1.0
048: * @author Doug Voet, April 2002
049: * @version $Revision: 1.11 $ ($Author: dvoet $)
050: */
051: public class EnhancedJarFile {
052: public static final String JAR_DELIMETER = "/";
053:
054: /**
055: * Provides a handle to Apache-commons logger
056: */
057: private Log log = LogFactory.getLog(this .getClass());
058:
059: private JarFile jar;
060:
061: /**
062: * @see java.util.jar.JarFile#JarFile(java.lang.String)
063: */
064: public EnhancedJarFile(String name) throws IOException {
065: if (log.isTraceEnabled()) {
066: log.trace("Openning Jar ["
067: + name
068: + "] "
069: + ExceptionUtility
070: .captureStackTrace(new Exception()));
071: }
072: this .jar = new JarFile(name);
073: }
074:
075: /**
076: * @see java.util.jar.JarFile#JarFile(java.lang.String, boolean)
077: */
078: public EnhancedJarFile(String name, boolean verify)
079: throws IOException {
080: if (log.isTraceEnabled()) {
081: log.trace("Openning Jar ["
082: + name
083: + "] "
084: + ExceptionUtility
085: .captureStackTrace(new Exception()));
086: }
087: this .jar = new JarFile(name, verify);
088: }
089:
090: /**
091: * @see java.util.jar.JarFile#JarFile(java.io.File)
092: */
093: public EnhancedJarFile(File file) throws IOException {
094: if (log.isTraceEnabled()) {
095: log.trace("Openning Jar ["
096: + file.getAbsolutePath()
097: + "] "
098: + ExceptionUtility
099: .captureStackTrace(new Exception()));
100: }
101: this .jar = new JarFile(file);
102: }
103:
104: /**
105: * @see java.util.jar.JarFile#JarFile(java.io.File, boolean)
106: */
107: public EnhancedJarFile(File file, boolean verify)
108: throws IOException {
109: if (log.isTraceEnabled()) {
110: log.trace("Openning Jar ["
111: + file.getAbsolutePath()
112: + "] "
113: + ExceptionUtility
114: .captureStackTrace(new Exception()));
115: }
116: this .jar = new JarFile(file, verify);
117: }
118:
119: /**
120: * @see java.util.jar.JarFile#JarFile(java.io.File, boolean, int)
121: */
122: public EnhancedJarFile(File file, boolean verify, int mode)
123: throws IOException {
124: if (log.isTraceEnabled()) {
125: log.trace("Openning Jar ["
126: + file.getAbsolutePath()
127: + "] "
128: + ExceptionUtility
129: .captureStackTrace(new Exception()));
130: }
131: this .jar = new JarFile(file, verify, mode);
132: }
133:
134: /**
135: * Returns a list of entries that are
136: * immediately below the entry named by entryName in the jar's directory
137: * structure.
138: *
139: * @param entryName the name of the directory entry name
140: * @return List a list of java.util.jar.JarEntry objects that are
141: * immediately below the entry named by entryName in the jar's directory
142: * structure.
143: */
144: public List listSubEntries(String entryName) {
145:
146: if (entryName == null) {
147: throw new InvalidParameterException(this .getClass(),
148: "Entry name cannot be null");
149: }
150:
151: Enumeration entries = jar.entries();
152: List subEntries = new ArrayList();
153:
154: while (entries.hasMoreElements()) {
155: JarEntry nextEntry = (JarEntry) entries.nextElement();
156:
157: if (nextEntry.getName().startsWith(entryName)) {
158: // the next entry name starts with the entryName so it
159: // is a potential sub entry
160:
161: // tokenize the rest of the next entry name to see how
162: // many tokens exist
163: StringTokenizer tokenizer = new StringTokenizer(
164: nextEntry.getName().substring(
165: entryName.length()),
166: EnhancedJarFile.JAR_DELIMETER);
167:
168: if (tokenizer.countTokens() == 1) {
169: // only 1 token exists, so it is a sub-entry
170: subEntries.add(nextEntry);
171: }
172: }
173: }
174:
175: return subEntries;
176: }
177:
178: /**
179: * Creates a new output entry stream within the jar. The entry named
180: * will be created if it does not exist within the jar already.
181: *
182: * @param entryName name of the entry for which to create an output
183: * stream.
184: * @return JarEntryOutputStream
185: */
186: public JarEntryOutputStream getEntryOutputStream(String entryName) {
187: return new JarEntryOutputStream(this , entryName);
188: }
189:
190: /**
191: * Removes the given entry from the jar. If the entry does not exist,
192: * the method returns without doing anything.
193: *
194: * @param entry entry to be removed
195: * @throws IOException if there is a problem writing the changes
196: * to the jar
197: */
198: public void removeEntry(JarEntry entry) throws IOException {
199: // opens an output stream and closes it without writing anything to it
200: if (entry != null && getEntry(entry.getName()) != null) {
201: JarEntryOutputStream outputStream = new JarEntryOutputStream(
202: this , entry.getName());
203:
204: outputStream.close();
205: }
206: }
207:
208: /**
209: * @see java.util.jar.JarFile#entries()
210: */
211: public Enumeration entries() {
212: return this .jar.entries();
213: }
214:
215: /**
216: * @see java.util.jar.JarFile#getEntry(java.lang.String)
217: */
218: public ZipEntry getEntry(String arg0) {
219: return this .jar.getEntry(arg0);
220: }
221:
222: /**
223: * @see java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
224: */
225: public InputStream getInputStream(ZipEntry arg0) throws IOException {
226: return this .jar.getInputStream(arg0);
227: }
228:
229: /**
230: * @see java.util.jar.JarFile#getJarEntry(java.lang.String)
231: */
232: public JarEntry getJarEntry(String arg0) {
233: return this .jar.getJarEntry(arg0);
234: }
235:
236: /**
237: * @see java.util.jar.JarFile#getManifest()
238: */
239: public Manifest getManifest() throws IOException {
240: return this .jar.getManifest();
241: }
242:
243: /**
244: * @see java.util.zip.ZipFile#close()
245: */
246: public void close() throws IOException {
247: if (log.isTraceEnabled()) {
248: log.trace("Closing Jar ["
249: + this .jar.getName()
250: + "] "
251: + ExceptionUtility
252: .captureStackTrace(new Exception()));
253: }
254: this .jar.close();
255: }
256:
257: /**
258: * @see java.util.zip.ZipFile#getName()
259: */
260: public String getName() {
261: return this .jar.getName();
262: }
263:
264: /**
265: * @see java.util.zip.ZipFile#size()
266: */
267: public int size() {
268: return this .jar.size();
269: }
270:
271: /**
272: * Utility method used to swap the underlying jar file out for the new one.
273: * This method closes the old jar file, deletes it, moves the new jar
274: * file to the location where the old one used to be and opens it.
275: * <p>
276: * This is used when modifying the jar (removal, addition, or changes
277: * of entries)
278: *
279: * @param newJarFile the file object pointing to the new jar file
280: */
281: void swapJars(File newJarFile) throws IOException {
282: File oldJarFile = new File(getName());
283: this .jar.close();
284: oldJarFile.delete();
285: if (newJarFile.renameTo(oldJarFile)) {
286: this .jar = new JarFile(oldJarFile);
287: } else {
288: throw new IOException();
289: }
290: }
291: }
|