package gov.nih.nci.cagrid.common;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.OutputStream;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
/**
* JarUtilities
* Utilities to manipulate jar files
*
* @author <A HREF="MAILTO:ervin@bmi.osu.edu">David W. Ervin</A>
*
* @created Oct 25, 2006
* @version $Id$
*/
public class JarUtilities {
/**
* Gets the contents of a jar entry as a StringBuffer
*
* @param jar
* The jar to extract from
* @param entryName
* The name of the entry to be extracted
* @return
* The contents of a jar entry, or null if no such entry exists
* @throws IOException
*/
public static StringBuffer getFileContents(JarFile jar, String entryName) throws IOException {
JarEntry entry = jar.getJarEntry(entryName);
if (entry == null) {
return null;
}
BufferedInputStream entryStream = new BufferedInputStream(jar.getInputStream(entry));
StringBuffer buffer = Utils.inputStreamToStringBuffer(entryStream);
return buffer;
}
/**
* Removes an entry from a jar file
*
* @param jar
* The jar file
* @param entryName
* The name of the entry to remove
* @return
* The data of the jar with the entry removed
* @throws IOException
*/
public static byte[] removeJarEntry(JarFile jar, String entryName) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
JarOutputStream jarOut = new JarOutputStream(bytes);
// copy all entries except the one with the matching name
Set<String> copiedEntries = new HashSet<String>();
Enumeration<JarEntry> jarEntries = jar.entries();
while (jarEntries.hasMoreElements()) {
JarEntry entry = jarEntries.nextElement();
String name = entry.getName();
if (!name.equals(entryName)) {
if (!copiedEntries.contains(name)) {
jarOut.putNextEntry(entry);
InputStream entryStream = jar.getInputStream(entry);
byte[] entryBytes = streamToBytes(entryStream);
entryStream.close();
jarOut.write(entryBytes);
jarOut.closeEntry();
copiedEntries.add(name);
}
}
}
jarOut.flush();
jarOut.close();
return bytes.toByteArray();
}
/**
* Places the contents of a directory in a Jar file
*
* @param dir
* The directory
* @param jarFile
* The jar file
* @throws IOException
*/
public static void jarDirectory(File dir, File jarFile) throws IOException {
JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(jarFile));
List<File> files = Utils.recursiveListFiles(dir, new FileFilter() {
public boolean accept(File name) {
return true;
}
});
int baseDirNameLength = dir.getAbsolutePath().length();
for (File fileToAdd : files) {
String relativeFileName = fileToAdd.getAbsolutePath().substring(baseDirNameLength + 1);
JarEntry entry = new JarEntry(relativeFileName);
jarOut.putNextEntry(entry);
if (!fileToAdd.isDirectory()) {
BufferedInputStream fileInput = new BufferedInputStream(new FileInputStream(fileToAdd));
copyStreams(fileInput, jarOut);
fileInput.close();
}
}
jarOut.flush();
jarOut.close();
}
/**
* Inserts an entry in a Jar file. If an entry with the given name is found,
* it will be replaced with the new one.
*
* @param jarFile
* The jar file to be appended
* @param entryName
* The name of the new entry
* @param data
* The data to add to the zip
* @throws IOException
*/
public static void insertEntry(File jarFile, String entryName, byte[] data) throws IOException {
// create a temp file
File tempJar = File.createTempFile(jarFile.getName(), "tmp");
tempJar.delete();
FileOutputStream tempOut = new FileOutputStream(tempJar);
JarOutputStream jarOut = new JarOutputStream(tempOut);
try {
// start streaming the input stream over to the temp
JarFile jarIn = new JarFile(jarFile);
Enumeration<JarEntry> entries = jarIn.entries();
while (entries.hasMoreElements()) {
JarEntry inputEntry = entries.nextElement();
if (!inputEntry.getName().equals(entryName)) {
InputStream entryStream = jarIn.getInputStream(inputEntry);
jarOut.putNextEntry(inputEntry);
copyStreams(entryStream, jarOut);
jarOut.closeEntry();
}
}
// create new entry
JarEntry insert = new JarEntry(entryName);
jarOut.putNextEntry(insert);
copyStreams(new ByteArrayInputStream(data), jarOut);
jarOut.closeEntry();
jarOut.close();
jarIn.close();
jarFile.delete();
Utils.copyFile(tempJar, jarFile);
} finally {
tempJar.delete();
}
}
/**
* Reads a stream and returns the byte content of it
* @param stream
* The stream
* @return
* The data of the stream
* @throws IOException
*/
private static byte[] streamToBytes(InputStream stream) throws IOException {
byte[] bytes = new byte[0];
byte[] buffer = new byte[8192];
int len = -1;
while ((len = stream.read(buffer)) != -1) {
byte[] temp = new byte[bytes.length + len];
System.arraycopy(bytes, 0, temp, 0, bytes.length);
System.arraycopy(buffer, 0, temp, bytes.length, len);
bytes = temp;
}
return bytes;
}
/**
* Copies the contents of an input stream into an output stream
*
* @param input
* @param output
* @throws IOException
*/
private static void copyStreams(InputStream input, OutputStream output) throws IOException {
byte[] temp = new byte[8192];
int read = -1;
while ((read = input.read(temp)) != -1) {
output.write(temp, 0, read);
}
}
}