/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.scheduler.common.util; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.zip.CRC32; import java.util.zip.ZipOutputStream; import org.objectweb.proactive.annotation.PublicAPI; /** * Utils for creating and reading jar files. * @author The ProActive Team */ @PublicAPI public class JarUtils extends ZipUtils { /** * Create a jar file that contains all the directory listed in directories parameter. * @param directoriesAndFiles the list of directories and files to be jarred. * @param manifestVerion the version of the jar manifest (can be null). * @param mainClass the main class of the jar (can be null). * @param jarInternalClasspath the class-path of the jar (can be null). * @param crc the CRC32 of all jar entries. Can be null if no crc is needed. * @throws IOException if the jar file cannot be created. * @return the jar file as a byte[]. */ public static byte[] jarDirectoriesAndFiles(String[] directoriesAndFiles, String manifestVerion, String mainClass, String jarInternalClasspath, CRC32 crc) throws IOException { // Fill in a byte array ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Create jar stream JarOutputStream jos = new JarOutputStream(baos, JarUtils.createManifest(manifestVerion, mainClass, jarInternalClasspath)); jos.setLevel(COMP_LEVEL); // Jar file is ready jarIt(jos, directoriesAndFiles, crc); // Close the file output streams jos.flush(); jos.close(); baos.flush(); baos.close(); return baos.toByteArray(); } /** * Jar directory content in the given output stream * * @param zos the output stream in which to store the jarred directory * @param directoriesAndFiles a list of directories and files to be jarred * @throws IOException if a jar entry cannot be created. */ protected static void jarIt(ZipOutputStream zos, String[] directoriesAndFiles, CRC32 crc) throws IOException { for (String pathElement : directoriesAndFiles) { File fileElement = new File(pathElement); //normalize path (also remove consecutive file separator) pathElement = fileElement.getPath(); if (fileElement.isFile()) { // add zip files at the root of the global jar file ! int length = pathElement.lastIndexOf(File.separator); if (length == -1) { length = 0; } zipFile(pathElement, length, zos, crc); } else if (fileElement.isDirectory()) { String strBaseFolder = pathElement.endsWith(File.separator) ? pathElement : pathElement + File.separator; zipDirectory(pathElement, strBaseFolder.length(), zos, crc); } } } private static Manifest createManifest(String manifestVerion, String mainClass, String jarInternalClasspath) { // Create manifest Manifest manifest = new Manifest(); Attributes manifestAttr = manifest.getMainAttributes(); //note:Must set Manifest-Version,or the manifest file will be empty! if (manifestVerion != null) { manifestAttr.putValue("Manifest-Version", manifestVerion); if (mainClass != null) { manifestAttr.putValue("Main-Class", mainClass); } if (jarInternalClasspath != null) { manifestAttr.putValue("Class-Path", jarInternalClasspath); } } return manifest; } /** * Create a jar file that contains all the directory listed in directories parameter and * store the create content in a file denoted by the path in the given dest argument * * @param directoriesAndFiles the directories and files to jar (recursively) * @param dest the jar destination file that will contains the jarred version of the first argument. * @param manifestVerion the version of the jar manifest (can be null). * @param mainClass the main class of the jar (can be null). * @param jarInternalClasspath the class-path of the jar (can be null). * @param crc the CRC32 of all ajr entries. Can be null if no crc is needed. * @throws IOException if the zip file cannot be created. */ public static void jar(String[] directoriesAndFiles, File dest, String manifestVerion, String mainClass, String jarInternalClasspath, CRC32 crc) throws IOException { byte[] jarred = jarDirectoriesAndFiles(directoriesAndFiles, manifestVerion, mainClass, jarInternalClasspath, crc); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest)); bos.write(jarred); bos.close(); } /** * Unjar a jar file into a directory. * * @param jarFile The jar file to be unjared. * @param dest the destination directory. * @throws IOException if the destination does not exist or is not a directory, or if the jar file cannot be extracted. */ public static void unjar(JarFile jarFile, File dest) throws IOException { unzip(jarFile, dest); } }