public void createInstaller() throws Exception { // preliminary work info.setInstallerBase(compilerData.getOutput().replaceAll(".jar", "")); packJarsSeparate = (info.getWebDirURL() != null); // primary (possibly only) jar. -1 indicates primary sendStart(); writeInstaller(); // Finish up. closeAlways is a hack for pack compressions other than // default. Some of it (e.g. BZip2) closes the slave of it also. // But this should not be because the jar stream should be open // for the next pack. Therefore an own JarOutputStream will be used // which close method will be blocked. primaryJarStream.closeAlways(); sendStop(); }
/** Write Packs to primary jar or each to a separate jar. */ protected void writePacks() throws Exception { final int num = packsList.size(); sendMsg("Writing " + num + " Pack" + (num > 1 ? "s" : "") + " into installer"); // Map to remember pack number and bytes offsets of back references Map<File, Object[]> storedFiles = new HashMap<File, Object[]>(); // Pack200 files map Map<Integer, File> pack200Map = new HashMap<Integer, File>(); int pack200Counter = 0; // Force UTF-8 encoding in order to have proper ZipEntry names. primaryJarStream.setEncoding("utf-8"); // First write the serialized files and file metadata data for each pack // while counting bytes. int packNumber = 0; IXMLElement root = new XMLElementImpl("packs"); for (PackInfo packInfo : packsList) { Pack pack = packInfo.getPack(); pack.nbytes = 0; if ((pack.id == null) || (pack.id.length() == 0)) { pack.id = pack.name; } // create a pack specific jar if required // REFACTOR : Repare web installer // REFACTOR : Use a mergeManager for each packages that will be added to the main merger // if (packJarsSeparate) { // See installer.Unpacker#getPackAsStream for the counterpart // String name = baseFile.getName() + ".pack-" + pack.id + ".jar"; // packStream = IoHelper.getJarOutputStream(name, baseFile.getParentFile()); // } sendMsg("Writing Pack " + packNumber + ": " + pack.name, PackagerListener.MSG_VERBOSE); // Retrieve the correct output stream org.apache.tools.zip.ZipEntry entry = new org.apache.tools.zip.ZipEntry(RESOURCES_PATH + "packs/pack-" + pack.id); primaryJarStream.putNextEntry(entry); primaryJarStream.flush(); // flush before we start counting ByteCountingOutputStream dos = new ByteCountingOutputStream(outputStream); ObjectOutputStream objOut = new ObjectOutputStream(dos); // We write the actual pack files objOut.writeInt(packInfo.getPackFiles().size()); for (PackFile packFile : packInfo.getPackFiles()) { boolean addFile = !pack.loose; boolean pack200 = false; File file = packInfo.getFile(packFile); if (file.getName().toLowerCase().endsWith(".jar") && info.isPack200Compression() && isNotSignedJar(file)) { packFile.setPack200Jar(true); pack200 = true; } // use a back reference if file was in previous pack, and in // same jar Object[] info = storedFiles.get(file); if (info != null && !packJarsSeparate) { packFile.setPreviousPackFileRef((String) info[0], (Long) info[1]); addFile = false; } objOut.writeObject(packFile); // base info if (addFile && !packFile.isDirectory()) { long pos = dos.getByteCount(); // get the position if (pack200) { /* * Warning! * * Pack200 archives must be stored in separated streams, as the Pack200 unpacker * reads the entire stream... * * See http://java.sun.com/javase/6/docs/api/java/util/jar/Pack200.Unpacker.html */ pack200Map.put(pack200Counter, file); objOut.writeInt(pack200Counter); pack200Counter = pack200Counter + 1; } else { FileInputStream inStream = new FileInputStream(file); long bytesWritten = IoHelper.copyStream(inStream, objOut); inStream.close(); if (bytesWritten != packFile.length()) { throw new IOException("File size mismatch when reading " + file); } } storedFiles.put(file, new Object[] {pack.id, pos}); } // even if not written, it counts towards pack size pack.nbytes += packFile.size(); } // Write out information about parsable files objOut.writeInt(packInfo.getParsables().size()); for (ParsableFile parsableFile : packInfo.getParsables()) { objOut.writeObject(parsableFile); } // Write out information about executable files objOut.writeInt(packInfo.getExecutables().size()); for (ExecutableFile executableFile : packInfo.getExecutables()) { objOut.writeObject(executableFile); } // Write out information about updatecheck files objOut.writeInt(packInfo.getUpdateChecks().size()); for (UpdateCheck updateCheck : packInfo.getUpdateChecks()) { objOut.writeObject(updateCheck); } // Cleanup objOut.flush(); if (!compressor.useStandardCompression()) { outputStream.close(); } primaryJarStream.closeEntry(); // close pack specific jar if required if (packJarsSeparate) { primaryJarStream.closeAlways(); } IXMLElement child = new XMLElementImpl("pack", root); child.setAttribute("nbytes", Long.toString(pack.nbytes)); child.setAttribute("name", pack.name); if (pack.id != null) { child.setAttribute("id", pack.id); } root.addChild(child); packNumber++; } // Now that we know sizes, write pack metadata to primary jar. primaryJarStream.putNextEntry(new org.apache.tools.zip.ZipEntry(RESOURCES_PATH + "packs.info")); ObjectOutputStream out = new ObjectOutputStream(primaryJarStream); out.writeInt(packsList.size()); for (PackInfo packInfo : packsList) { out.writeObject(packInfo.getPack()); } out.flush(); primaryJarStream.closeEntry(); // Pack200 files Pack200.Packer packer = createAgressivePack200Packer(); for (Integer key : pack200Map.keySet()) { File file = pack200Map.get(key); primaryJarStream.putNextEntry( new org.apache.tools.zip.ZipEntry(RESOURCES_PATH + "packs/pack200-" + key)); JarFile jar = new JarFile(file); packer.pack(jar, primaryJarStream); jar.close(); primaryJarStream.closeEntry(); } }