001: package csdl.jblanket.util;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.FileOutputStream;
006: import java.io.InputStream;
007: import java.io.IOException;
008:
009: import java.util.Enumeration;
010: import java.util.jar.JarEntry;
011: import java.util.jar.JarException;
012: import java.util.jar.JarFile;
013: import java.util.jar.JarOutputStream;
014: import java.util.zip.CRC32;
015:
016: import org.apache.tools.ant.DirectoryScanner;
017:
018: /**
019: * Provides utilities to extract or package JAR files.
020: * <p>
021: * Methods are provided to either extract or package JAR files using the JDK1.2 java.util.jar
022: * package. Noted that JAR files created with the <code>jar</code> method are smaller than their
023: * counterpart created by using the <code>jar</code> command provided by Java. This is probably
024: * because the <code>jar</code> method here does not include any options.
025: * <p>
026: * Code snips from: Java Cookbook, pp 268-270 and The Java Class Libraries, pp 487-488
027: *
028: * @author Joy M. Agustin
029: * @version $Id: JarFactory.java,v 1.1 2004/11/07 00:32:24 timshadel Exp $
030: */
031: public class JarFactory {
032:
033: /** Buffer for reading/writing the JarFile data */
034: private byte[] buffer;
035:
036: /** Directory to that does/will contain the class files */
037: private String dir;
038:
039: /** Directory separator */
040: private static final String SLASH = File.separator;
041: /** Name of directory holding manifest file */
042: private static final String MAN_DIR = "META-INF";
043: /** Relative path to the manifest file starting at MAN_DIR */
044: private static final String MAN_FILE_PATH = MAN_DIR + SLASH
045: + "MANIFEST.MF";
046:
047: /**
048: * Constructs an JarFactory object.
049: *
050: * @param dir the directory that contains/will contain the class files.
051: */
052: public JarFactory(String dir) {
053:
054: this .dir = dir;
055: this .buffer = new byte[8092];
056: }
057:
058: /**
059: * Extracts all files in a JAR file.
060: *
061: * @param jarFile the JAR file to unjar.
062: * @throws IOException if cannot unjar <code>fileName</code>.
063: * @throws JarException if error extracting files from JAR file.
064: */
065: public void unJar(File jarFile) throws IOException, JarException {
066:
067: if (!jarFile.getName().endsWith(".jar")) {
068: throw new JarException("Not a zip file? "
069: + jarFile.getName());
070: }
071:
072: // process all entries in that JAR file
073: JarFile jar = new JarFile(jarFile);
074: Enumeration all = jar.entries();
075: while (all.hasMoreElements()) {
076: getEntry(jar, ((JarEntry) (all.nextElement())));
077: }
078:
079: jar.close();
080: }
081:
082: /**
083: * Gets one file <code>entry</code> from <code>jarFile</code>.
084: *
085: * @param jarFile the JAR file reference to retrieve <code>entry</code> from.
086: * @param entry the file from the JAR to extract.
087: * @throws IOException if error trying to read entry.
088: */
089: private void getEntry(JarFile jarFile, JarEntry entry)
090: throws IOException {
091:
092: String entryName = entry.getName();
093: // if a directory, mkdir it (remember to create intervening subdirectories if needed!)
094: if (entryName.endsWith("/")) {
095: new File(dir, entryName).mkdirs();
096: return;
097: }
098:
099: File f = new File(dir, entryName);
100:
101: if (!f.getParentFile().exists()) {
102: f.getParentFile().mkdirs();
103: }
104:
105: // Must be a file; create output stream to the file
106: FileOutputStream fostream = new FileOutputStream(f);
107: InputStream istream = jarFile.getInputStream(entry);
108:
109: // extract files
110: int n = 0;
111: while ((n = istream.read(buffer)) > 0) {
112: fostream.write(buffer, 0, n);
113: }
114:
115: try {
116: istream.close();
117: fostream.close();
118: } catch (IOException e) {
119: // do nothing -- following "Java Examples in a Nutshell" from O'Reilly
120: }
121: }
122:
123: /**
124: * Creates a JAR file. If the JAR file already exists, it will be overwritten.
125: *
126: * @param jarFile the JAR file to create.
127: * @throws IOException if cannot create JAR file.
128: * @throws JarException if error putting files into JAR file.
129: */
130: public void jar(File jarFile) throws IOException, JarException {
131:
132: if (!jarFile.getName().endsWith(".jar")) {
133: throw new JarException("Not a zip file? "
134: + jarFile.getName());
135: }
136:
137: // get all files to include in JAR file, except for manifest
138: DirectoryScanner scanner = new DirectoryScanner();
139: scanner.setIncludes(new String[] { "**" });
140: scanner.setExcludes(new String[] { "**" + SLASH + MAN_DIR
141: + SLASH + "**" });
142: scanner.setBasedir(new File(this .dir));
143: scanner.setCaseSensitive(true);
144: scanner.scan();
145: String[] directories = scanner.getIncludedDirectories();
146: String[] files = scanner.getIncludedFiles();
147:
148: // create JAR file
149: FileOutputStream fostream = new FileOutputStream(jarFile);
150: JarOutputStream jostream = new JarOutputStream(fostream);
151:
152: // create manifest directory and manifest
153: if ((new File(dir, MAN_DIR)).exists()) {
154: putManifest(jostream);
155: }
156:
157: //create subdirectories
158: String currentDirectory = "";
159: for (int i = 0; i < directories.length; i++) {
160: // do not need to put the current directory in JAR file
161: if (directories[i].equals(currentDirectory)) {
162: continue;
163: }
164: putEntry(directories[i] + SLASH, jostream);
165: }
166:
167: // create files
168: for (int i = 0; i < files.length; i++) {
169: putEntry(files[i], jostream);
170: }
171:
172: jostream.finish();
173:
174: try {
175: jostream.close();
176: fostream.close();
177: } catch (IOException e) {
178: // do nothing -- following "Java Examples in a Nutshell" from O'Reilly
179: }
180: }
181:
182: /**
183: * Puts manifest file into a JAR file.
184: *
185: * @param jostream the JAR file to put manifest into.
186: * @throws IOException if error trying to write entry.
187: */
188: private void putManifest(JarOutputStream jostream)
189: throws IOException {
190:
191: // begin borrowed code from Ant Jar and Zip classes
192: // put the META-INF directory into JAR file.
193: String manDirPath = MAN_DIR + SLASH;
194: JarEntry manifestDirEntry = new JarEntry(manDirPath.replace(
195: File.separatorChar, '/'));
196: manifestDirEntry.setTime(System.currentTimeMillis());
197: manifestDirEntry.setSize(0);
198: manifestDirEntry.setMethod(JarEntry.STORED);
199:
200: // This is faintly ridiculous - empty CRC value
201: manifestDirEntry.setCrc((new CRC32()).getValue());
202: jostream.putNextEntry(manifestDirEntry);
203:
204: // now put the manifest file into JAR file.
205: JarEntry manifestFileEntry = new JarEntry(MAN_FILE_PATH
206: .replace(File.separatorChar, '/'));
207: manifestFileEntry.setTime(System.currentTimeMillis());
208: FileInputStream fistream = new FileInputStream(new File(
209: this .dir, MAN_FILE_PATH));
210: jostream.putNextEntry(manifestFileEntry);
211:
212: int n = 0;
213: while ((n = fistream.read(buffer)) >= 0) {
214: jostream.write(buffer, 0, n);
215: }
216: jostream.closeEntry();
217:
218: // end borrowed code from Ant Jar and Zip classes
219: try {
220: fistream.close();
221: } catch (IOException e) {
222: // do nothing -- following "Java Examples in a Nutshell" from O'Reilly
223: }
224: }
225:
226: /**
227: * Puts a file into a JAR file.
228: *
229: * @param fileName the file to put in the JAR.
230: * @param jostream the JAR file to put <code>fileName</code> into.
231: * @throws IOException if error trying to write entry.
232: */
233: private void putEntry(String fileName, JarOutputStream jostream)
234: throws IOException {
235:
236: // prepare fileName for entry into JAR file
237: String entryName = fileName.replace(File.separatorChar, '/');
238:
239: // put directory (remember to create intervening subdirectories if needed!)
240: if (entryName.endsWith("/")) {
241: jostream.putNextEntry(new JarEntry(entryName));
242: jostream.closeEntry();
243: return;
244: }
245:
246: // put file
247: FileInputStream fistream = new FileInputStream(new File(
248: this .dir, fileName));
249: jostream.putNextEntry(new JarEntry(entryName));
250: int n;
251:
252: // now read and write the JAR entry data.
253: while ((n = fistream.read(buffer)) >= 0) {
254: jostream.write(buffer, 0, n);
255: }
256:
257: jostream.closeEntry();
258:
259: try {
260: fistream.close();
261: } catch (IOException e) {
262: // do nothing -- following "Java Examples in a Nutshell" from O'Reilly
263: }
264: }
265: }
|