package org.eclipse.buckminster.jarprocessor; 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.io.OutputStream; import java.util.List; import java.util.jar.JarFile; import java.util.jar.Pack200.Packer; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.eclipse.buckminster.core.helpers.FileUtils; import org.eclipse.buckminster.runtime.Buckminster; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.Logger; import org.eclipse.core.runtime.CoreException; public class RecursivePacker extends RecursivePack200 { private final boolean useRedunantGZipping; public RecursivePacker(File tempDir, List<String> defaultArgs, boolean useRedundantGZipping) { super(tempDir, defaultArgs); this.useRedunantGZipping = useRedundantGZipping; } public boolean pack(File jarFile, File destFolder, boolean retainUnpacked) throws CoreException { Logger log = Buckminster.getLogger(); String fileName = jarFile.getAbsolutePath(); InputStream input = null; OutputStream output = null; boolean sharedFolder; if (destFolder == null) { sharedFolder = true; destFolder = jarFile.getParentFile(); } else sharedFolder = destFolder.equals(jarFile.getParentFile()); try { input = new ZipInputStream(new FileInputStream(jarFile)); JarInfo jarInfo = JarInfo.getJarInfo(null, fileName, (ZipInputStream) input); IOUtils.close(input); input = null; if (!(jarInfo.hasClasses() || (jarInfo.isNested() && !jarInfo.isExcludeChildrenPack()))) { log.debug("Packer: Skipping %s since it contains no classes and no nested jars to pack", fileName); //$NON-NLS-1$ if (!sharedFolder) FileUtils.copyFile(jarFile, destFolder, jarFile.getName(), null); return false; } if (jarInfo.isExcludePack()) { log.debug("Packer: Skipping %s since is excluded", fileName); //$NON-NLS-1$ if (!sharedFolder) FileUtils.copyFile(jarFile, destFolder, jarFile.getName(), null); return false; } if (jarInfo.isSigned() && !jarInfo.isConditioned()) { log.debug("Packer: Skipping %s since is signed but not conditioned", fileName); //$NON-NLS-1$ if (!sharedFolder) FileUtils.copyFile(jarFile, destFolder, jarFile.getName(), null); return false; } File packedFile = new File(destFolder, jarFile.getName() + PACK_GZ_SUFFIX); input = new FileInputStream(jarFile); output = new BufferedOutputStream(new FileOutputStream(packedFile)); output = new BufferedOutputStream(new GZIPOutputStream(output)); // We must refrain from nested packing if // a) Nested packing is excluded using excludeChildrenPack // b) This jar has classes and is signed. That's because if we // change the nested file, the // CP tables used when normalizing will change, and thus, the packed // classes will change. // if (jarInfo.isNested()) nestedPack(input, jarInfo, output); else pack(jarInfo, input, output); IOUtils.close(input); input = null; if (sharedFolder) { if (!retainUnpacked) jarFile.delete(); } else { if (retainUnpacked) FileUtils.copyFile(jarFile, destFolder, jarFile.getName(), null); } return true; } catch (IOException e) { throw BuckminsterException.fromMessage(e, "Unable to pack %s", fileName); //$NON-NLS-1$ } finally { IOUtils.close(input); IOUtils.close(output); } } protected void nestedPack(final InputStream input, final JarInfo jarInfo, OutputStream packedOut) throws IOException, CoreException { File packInputFile = null; try { tempDir.mkdirs(); packInputFile = File.createTempFile("conditioned_", ".jar", tempDir); //$NON-NLS-1$//$NON-NLS-2$ OutputStream tempOut = null; try { tempOut = new BufferedOutputStream(new FileOutputStream(packInputFile)); processNestedJars(new ZipInputStream(input), jarInfo, tempOut); } finally { IOUtils.close(tempOut); } Packer packer = getPacker(jarInfo); packer.pack(new JarFile(packInputFile), packedOut); } finally { if (packInputFile != null) packInputFile.delete(); } } private void processNestedJars(ZipInputStream jarIn, JarInfo jarInfo, OutputStream output) throws IOException, CoreException { Logger log = Buckminster.getLogger(); ZipOutputStream jarOut = new ZipOutputStream(output); ZipEntry entry; boolean packChildren = !jarInfo.isExcludeChildrenPack(); while ((entry = jarIn.getNextEntry()) != null) { String name = entry.getName(); if (name.endsWith(JAR_SUFFIX)) { JarInfo nested = jarInfo.getNestedInfo(name); if (nested != null) { if (!packChildren) log.debug("Packer: Skipping recursive pack of %s since parent has children pack disabled", name); //$NON-NLS-1$ else if (nested.isSigned() && !nested.isConditioned()) log.debug("Packer: Skipping recursive pack of %s since it is signed but not conditioned", name); //$NON-NLS-1$ else if (jarInfo.hasClasses() && jarInfo.isSigned()) { log.debug("Packer: Skipping recursive pack of %s since parent is signed and has classes", name); //$NON-NLS-1$ } else { if (useRedunantGZipping) { jarOut.putNextEntry(createEntry(entry, name + PACK_GZ_SUFFIX)); GZIPOutputStream gzipOut = new GZIPOutputStream(jarOut); log.debug("Packer: Recursive gzipped pack of %s", name); //$NON-NLS-1$ nestedPack(jarIn, nested, gzipOut); gzipOut.finish(); } else { log.debug("Packer: Recursive pack of %s", name); //$NON-NLS-1$ jarOut.putNextEntry(createEntry(entry, name + PACK_SUFFIX)); nestedPack(jarIn, nested, jarOut); } continue; } } } jarOut.putNextEntry(createEntry(entry)); if (!entry.isDirectory()) IOUtils.copy(jarIn, jarOut, null); } jarOut.finish(); } }