Example usage for java.util.jar JarFile JarFile

List of usage examples for java.util.jar JarFile JarFile

Introduction

In this page you can find the example usage for java.util.jar JarFile JarFile.

Prototype

public JarFile(File file, boolean verify) throws IOException 

Source Link

Document

Creates a new JarFile to read from the specified File object.

Usage

From source file:com.liferay.ide.maven.core.util.DefaultMaven2OsgiConverter.java

private String getGroupIdFromPackage(File artifactFile) {
    try {//  w w  w. j av  a  2 s. c  om
        /* get package names from jar */
        Set packageNames = new HashSet();
        JarFile jar = new JarFile(artifactFile, false);
        Enumeration entries = jar.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();
            if (entry.getName().endsWith(".class")) {
                File f = new File(entry.getName());
                String packageName = f.getParent();
                if (packageName != null) {
                    packageNames.add(packageName);
                }
            }
        }

        /* find the top package */
        String[] groupIdSections = null;
        for (Iterator it = packageNames.iterator(); it.hasNext();) {
            String packageName = (String) it.next();

            String[] packageNameSections = packageName.split("\\" + FILE_SEPARATOR);
            if (groupIdSections == null) {
                /* first candidate */
                groupIdSections = packageNameSections;
            } else
            // if ( packageNameSections.length < groupIdSections.length )
            {
                /*
                 * find the common portion of current package and previous selected groupId
                 */
                int i;
                for (i = 0; (i < packageNameSections.length) && (i < groupIdSections.length); i++) {
                    if (!packageNameSections[i].equals(groupIdSections[i])) {
                        break;
                    }
                }
                groupIdSections = new String[i];
                System.arraycopy(packageNameSections, 0, groupIdSections, 0, i);
            }
        }

        if ((groupIdSections == null) || (groupIdSections.length == 0)) {
            return null;
        }

        /* only one section as id doesn't seem enough, so ignore it */
        if (groupIdSections.length == 1) {
            return null;
        }

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < groupIdSections.length; i++) {
            sb.append(groupIdSections[i]);
            if (i < groupIdSections.length - 1) {
                sb.append('.');
            }
        }
        return sb.toString();
    } catch (IOException e) {
        /* we took all the precautions to avoid this */
        throw new RuntimeException(e);
    }
}

From source file:com.jrummyapps.busybox.utils.ZipSigner.java

/**
 * Tool to sign JAR files (including APKs and OTA updates) in a way compatible with the mincrypt verifier, using
 * SHA1 and RSA keys.//  w  w w  .ja v  a  2  s . c  om
 *
 * @param unsignedZip
 *     The path to the APK, ZIP, JAR to sign
 * @param destination
 *     The output file
 * @return true if successfully signed the file
 */
public static boolean signZip(File unsignedZip, File destination) {
    final AssetManager am = App.getContext().getAssets();
    JarArchiveOutputStream outputJar = null;
    JarFile inputJar = null;

    try {
        X509Certificate publicKey = readPublicKey(am.open(PUBLIC_KEY));
        PrivateKey privateKey = readPrivateKey(am.open(PRIVATE_KEY));

        // Assume the certificate is valid for at least an hour.
        long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;

        inputJar = new JarFile(unsignedZip, false); // Don't verify.
        FileOutputStream stream = new FileOutputStream(destination);
        outputJar = new JarArchiveOutputStream(stream);
        outputJar.setLevel(9);

        // MANIFEST.MF
        Manifest manifest = addDigestsToManifest(inputJar);
        JarArchiveEntry je = new JarArchiveEntry(JarFile.MANIFEST_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);
        manifest.write(outputJar);

        ZipSignature signature1 = new ZipSignature();
        signature1.initSign(privateKey);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        writeSignatureFile(manifest, out);

        // CERT.SF
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(privateKey);
        je = new JarArchiveEntry(CERT_SF_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);
        byte[] sfBytes = writeSignatureFile(manifest, new SignatureOutputStream(outputJar, signature));

        signature1.update(sfBytes);
        byte[] signatureBytes = signature1.sign();

        // CERT.RSA
        je = new JarArchiveEntry(CERT_RSA_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);

        outputJar.write(readContentAsBytes(am.open(TEST_KEY)));
        outputJar.write(signatureBytes);

        copyFiles(manifest, inputJar, outputJar, timestamp);
    } catch (Exception e) {
        Crashlytics.logException(e);
        return false;
    } finally {
        IoUtils.closeQuietly(inputJar);
        IoUtils.closeQuietly(outputJar);
    }
    return true;
}

From source file:com.jrummyapps.busybox.signing.ZipSigner.java

/**
 * Tool to sign JAR files (including APKs and OTA updates) in a way compatible with the mincrypt verifier, using
 * SHA1 and RSA keys./*from ww  w.j av a2 s . co  m*/
 *
 * @param unsignedZip
 *     The path to the APK, ZIP, JAR to sign
 * @param destination
 *     The output file
 * @return true if successfully signed the file
 */
public static boolean signZip(File unsignedZip, File destination) {
    final AssetManager am = App.getContext().getAssets();
    JarArchiveOutputStream outputJar = null;
    JarFile inputJar = null;

    try {
        X509Certificate publicKey = readPublicKey(am.open(PUBLIC_KEY));
        PrivateKey privateKey = readPrivateKey(am.open(PRIVATE_KEY));

        // Assume the certificate is valid for at least an hour.
        long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;

        inputJar = new JarFile(unsignedZip, false); // Don't verify.
        FileOutputStream stream = new FileOutputStream(destination);
        outputJar = new JarArchiveOutputStream(stream);
        outputJar.setLevel(9);

        // MANIFEST.MF
        Manifest manifest = addDigestsToManifest(inputJar);
        JarArchiveEntry je = new JarArchiveEntry(JarFile.MANIFEST_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);
        manifest.write(outputJar);

        ZipSignature signature1 = new ZipSignature();
        signature1.initSign(privateKey);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        writeSignatureFile(manifest, out);

        // CERT.SF
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(privateKey);
        je = new JarArchiveEntry(CERT_SF_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);
        byte[] sfBytes = writeSignatureFile(manifest, new SignatureOutputStream(outputJar, signature));

        signature1.update(sfBytes);
        byte[] signatureBytes = signature1.sign();

        // CERT.RSA
        je = new JarArchiveEntry(CERT_RSA_NAME);
        je.setTime(timestamp);
        outputJar.putArchiveEntry(je);

        outputJar.write(readContentAsBytes(am.open(TEST_KEY)));
        outputJar.write(signatureBytes);

        copyFiles(manifest, inputJar, outputJar, timestamp);
    } catch (Exception e) {
        Crashlytics.logException(e);
        return false;
    } finally {
        IOUtils.closeQuietly(inputJar);
        IOUtils.closeQuietly(outputJar);
    }
    return true;
}

From source file:JarEntryOutputStream.java

/**
 * @see java.util.jar.JarFile#JarFile(java.lang.String, boolean)
 *///from  ww  w . j av  a2  s .c  o  m
public EnhancedJarFile(String name, boolean verify) throws IOException {

    this.jar = new JarFile(name, verify);
}

From source file:JarEntryOutputStream.java

/**
 * @see java.util.jar.JarFile#JarFile(java.io.File, boolean)
 *//*from w w  w .j a  va  2  s.c  om*/
public EnhancedJarFile(File file, boolean verify) throws IOException {

    this.jar = new JarFile(file, verify);
}

From source file:com.slamd.admin.JobPack.java

/**
 * Extracts the contents of the job pack and registers the included jobs with
 * the SLAMD server./*  w  w  w  .jav  a 2s  .c  om*/
 *
 * @throws  SLAMDServerException  If a problem occurs while processing the job
 *                                pack JAR file.
 */
public void processJobPack() throws SLAMDServerException {
    byte[] fileData = null;
    File tempFile = null;
    String fileName = null;
    String separator = System.getProperty("file.separator");

    if (filePath == null) {
        // First, get the request and ensure it is multipart content.
        HttpServletRequest request = requestInfo.request;
        if (!FileUpload.isMultipartContent(request)) {
            throw new SLAMDServerException("Request does not contain multipart " + "content");
        }

        // Iterate through the request fields to get to the file data.
        Iterator iterator = fieldList.iterator();
        while (iterator.hasNext()) {
            FileItem fileItem = (FileItem) iterator.next();
            String fieldName = fileItem.getFieldName();

            if (fieldName.equals(Constants.SERVLET_PARAM_JOB_PACK_FILE)) {
                fileData = fileItem.get();
                fileName = fileItem.getName();
            }
        }

        // Make sure that a file was actually uploaded.
        if (fileData == null) {
            throw new SLAMDServerException("No file data was found in the " + "request.");
        }

        // Write the JAR file data to a temp file, since that's the only way we
        // can parse it.
        if (separator == null) {
            separator = "/";
        }

        tempFile = new File(jobClassDirectory + separator + fileName);
        try {
            FileOutputStream outputStream = new FileOutputStream(tempFile);
            outputStream.write(fileData);
            outputStream.flush();
            outputStream.close();
        } catch (IOException ioe) {
            try {
                tempFile.delete();
            } catch (Exception e) {
            }

            ioe.printStackTrace();
            slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(ioe));
            throw new SLAMDServerException("I/O error writing temporary JAR " + "file:  " + ioe, ioe);
        }
    } else {
        tempFile = new File(filePath);
        if ((!tempFile.exists()) || (!tempFile.isFile())) {
            throw new SLAMDServerException("Specified job pack file \"" + filePath + "\" does not exist");
        }

        try {
            fileName = tempFile.getName();
            int fileLength = (int) tempFile.length();
            fileData = new byte[fileLength];

            FileInputStream inputStream = new FileInputStream(tempFile);
            int bytesRead = 0;
            while (bytesRead < fileLength) {
                bytesRead += inputStream.read(fileData, bytesRead, fileLength - bytesRead);
            }
            inputStream.close();
        } catch (Exception e) {
            slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e));
            throw new SLAMDServerException("Error reading job pack file \"" + filePath + "\" -- " + e, e);
        }
    }

    StringBuilder htmlBody = requestInfo.htmlBody;

    // Parse the jar file
    JarFile jarFile = null;
    Manifest manifest = null;
    Enumeration jarEntries = null;
    try {
        jarFile = new JarFile(tempFile, true);
        manifest = jarFile.getManifest();
        jarEntries = jarFile.entries();
    } catch (IOException ioe) {
        try {
            if (filePath == null) {
                tempFile.delete();
            }
        } catch (Exception e) {
        }

        ioe.printStackTrace();
        slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(ioe));
        throw new SLAMDServerException("Unable to parse the JAR file:  " + ioe, ioe);
    }

    ArrayList<String> dirList = new ArrayList<String>();
    ArrayList<String> fileNameList = new ArrayList<String>();
    ArrayList<byte[]> fileDataList = new ArrayList<byte[]>();
    while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
        String entryName = jarEntry.getName();
        if (jarEntry.isDirectory()) {
            dirList.add(entryName);
        } else {
            try {
                int entrySize = (int) jarEntry.getSize();
                byte[] entryData = new byte[entrySize];
                InputStream inputStream = jarFile.getInputStream(jarEntry);
                extractFileData(inputStream, entryData);
                fileNameList.add(entryName);
                fileDataList.add(entryData);
            } catch (IOException ioe) {
                try {
                    jarFile.close();
                    if (filePath == null) {
                        tempFile.delete();
                    }
                } catch (Exception e) {
                }

                ioe.printStackTrace();
                slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(ioe));
                throw new SLAMDServerException("I/O error parsing JAR entry " + entryName + " -- " + ioe, ioe);
            } catch (SLAMDServerException sse) {
                try {
                    jarFile.close();
                    if (filePath == null) {
                        tempFile.delete();
                    }
                } catch (Exception e) {
                }

                sse.printStackTrace();
                throw sse;
            }
        }
    }

    // If we have gotten here, then we have read all the data from the JAR file.
    // Delete the temporary file to prevent possible (although unlikely)
    // conflicts with data contained in the JAR.
    try {
        jarFile.close();
        if (filePath == null) {
            tempFile.delete();
        }
    } catch (Exception e) {
    }

    // Create the directory structure specified in the JAR file.
    if (!dirList.isEmpty()) {
        htmlBody.append("<B>Created the following directories</B>" + Constants.EOL);
        htmlBody.append("<BR>" + Constants.EOL);
        htmlBody.append("<UL>" + Constants.EOL);

        for (int i = 0; i < dirList.size(); i++) {
            File dirFile = new File(jobClassDirectory + separator + dirList.get(i));
            try {
                dirFile.mkdirs();
                htmlBody.append("  <LI>" + dirFile.getAbsolutePath() + "</LI>" + Constants.EOL);
            } catch (Exception e) {
                htmlBody.append("</UL>" + Constants.EOL);
                e.printStackTrace();
                slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(e));
                throw new SLAMDServerException(
                        "Unable to create directory \"" + dirFile.getAbsolutePath() + " -- " + e, e);
            }
        }

        htmlBody.append("</UL>" + Constants.EOL);
        htmlBody.append("<BR><BR>" + Constants.EOL);
    }

    // Write all the files to disk.  If we have gotten this far, then there
    // should not be any failures, but if there are, then we will have to
    // leave things in a "dirty" state.
    if (!fileNameList.isEmpty()) {
        htmlBody.append("<B>Created the following files</B>" + Constants.EOL);
        htmlBody.append("<BR>" + Constants.EOL);
        htmlBody.append("<UL>" + Constants.EOL);

        for (int i = 0; i < fileNameList.size(); i++) {
            File dataFile = new File(jobClassDirectory + separator + fileNameList.get(i));

            try {
                // Make sure the parent directory exists.
                dataFile.getParentFile().mkdirs();
            } catch (Exception e) {
            }

            try {
                FileOutputStream outputStream = new FileOutputStream(dataFile);
                outputStream.write(fileDataList.get(i));
                outputStream.flush();
                outputStream.close();
                htmlBody.append("  <LI>" + dataFile.getAbsolutePath() + "</LI>" + Constants.EOL);
            } catch (IOException ioe) {
                htmlBody.append("</UL>" + Constants.EOL);
                ioe.printStackTrace();
                slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG, JobClass.stackTraceToString(ioe));
                throw new SLAMDServerException("Unable to write file " + dataFile.getAbsolutePath() + ioe, ioe);
            }
        }

        htmlBody.append("</UL>" + Constants.EOL);
        htmlBody.append("<BR><BR>" + Constants.EOL);
    }

    // Finally, parse the manifest to get the names of the classes that should
    // be registered with the SLAMD server.
    Attributes manifestAttributes = manifest.getMainAttributes();
    Attributes.Name key = new Attributes.Name(Constants.JOB_PACK_MANIFEST_REGISTER_JOBS_ATTR);
    String registerClassesStr = (String) manifestAttributes.get(key);
    if ((registerClassesStr == null) || (registerClassesStr.length() == 0)) {
        htmlBody.append("<B>No job classes registered</B>" + Constants.EOL);
    } else {
        ArrayList<String> successList = new ArrayList<String>();
        ArrayList<String> failureList = new ArrayList<String>();

        StringTokenizer tokenizer = new StringTokenizer(registerClassesStr, ", \t\r\n");
        while (tokenizer.hasMoreTokens()) {
            String className = tokenizer.nextToken();

            try {
                JobClass jobClass = slamdServer.loadJobClass(className);
                slamdServer.addJobClass(jobClass);
                successList.add(className);
            } catch (Exception e) {
                failureList.add(className + ":  " + e);
            }
        }

        if (!successList.isEmpty()) {
            htmlBody.append("<B>Registered Job Classes</B>" + Constants.EOL);
            htmlBody.append("<UL>" + Constants.EOL);
            for (int i = 0; i < successList.size(); i++) {
                htmlBody.append("  <LI>" + successList.get(i) + "</LI>" + Constants.EOL);
            }
            htmlBody.append("</UL>" + Constants.EOL);
            htmlBody.append("<BR><BR>" + Constants.EOL);
        }

        if (!failureList.isEmpty()) {
            htmlBody.append("<B>Unable to Register Job Classes</B>" + Constants.EOL);
            htmlBody.append("<UL>" + Constants.EOL);
            for (int i = 0; i < failureList.size(); i++) {
                htmlBody.append("  <LI>" + failureList.get(i) + "</LI>" + Constants.EOL);
            }
            htmlBody.append("</UL>" + Constants.EOL);
            htmlBody.append("<BR><BR>" + Constants.EOL);
        }
    }
}

From source file:edu.cmu.tetrad.cli.util.Args.java

public static void showHelp(String algorithmName, Options options) {
    StringBuilder sb = new StringBuilder("java -jar");
    try {//from  www  . j  a v  a 2  s.com
        JarFile jarFile = new JarFile(Args.class.getProtectionDomain().getCodeSource().getLocation().getPath(),
                true);
        Manifest manifest = jarFile.getManifest();
        Attributes attributes = manifest.getMainAttributes();
        String artifactId = attributes.getValue("Implementation-Title");
        String version = attributes.getValue("Implementation-Version");
        sb.append(String.format(" %s-%s.jar", artifactId, version));
    } catch (IOException exception) {
        sb.append(" causal-cmd.jar");
    }
    sb.append(" --algorithm ");
    sb.append(algorithmName);

    HelpFormatter formatter = new HelpFormatter();
    formatter.setWidth(-1);
    formatter.printHelp(sb.toString(), options, true);
}

From source file:org.apache.maven.plugin.internal.DefaultMavenPluginManager.java

private PluginDescriptor extractPluginDescriptor(Artifact pluginArtifact, Plugin plugin)
        throws PluginDescriptorParsingException, InvalidPluginDescriptorException {
    PluginDescriptor pluginDescriptor = null;

    File pluginFile = pluginArtifact.getFile();

    try {// w ww.j av a 2 s  .co  m
        if (pluginFile.isFile()) {
            try (JarFile pluginJar = new JarFile(pluginFile, false)) {
                ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getPluginDescriptorLocation());

                if (pluginDescriptorEntry != null) {
                    InputStream is = pluginJar.getInputStream(pluginDescriptorEntry);

                    pluginDescriptor = parsePluginDescriptor(is, plugin, pluginFile.getAbsolutePath());
                }
            }
        } else {
            File pluginXml = new File(pluginFile, getPluginDescriptorLocation());

            if (pluginXml.isFile()) {
                try (InputStream is = new BufferedInputStream(new FileInputStream(pluginXml))) {
                    pluginDescriptor = parsePluginDescriptor(is, plugin, pluginXml.getAbsolutePath());
                }
            }
        }

        if (pluginDescriptor == null) {
            throw new IOException("No plugin descriptor found at " + getPluginDescriptorLocation());
        }
    } catch (IOException e) {
        throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e);
    }

    MavenPluginValidator validator = new MavenPluginValidator(pluginArtifact);

    validator.validate(pluginDescriptor);

    if (validator.hasErrors()) {
        throw new InvalidPluginDescriptorException(
                "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")",
                validator.getErrors());
    }

    pluginDescriptor.setPluginArtifact(pluginArtifact);

    return pluginDescriptor;
}

From source file:jenkins.security.ClassFilterImpl.java

private boolean isLocationWhitelisted(String _loc) {
    return codeSourceCache.computeIfAbsent(_loc, loc -> {
        if (loc.equals(JENKINS_LOC)) {
            LOGGER.log(Level.FINE, "{0} seems to be the location of Jenkins core, OK", loc);
            return true;
        }//from w  ww . j ava  2 s  .co m
        if (loc.equals(REMOTING_LOC)) {
            LOGGER.log(Level.FINE, "{0} seems to be the location of Remoting, OK", loc);
            return true;
        }
        if (loc.matches("file:/.+[.]jar")) {
            try (JarFile jf = new JarFile(new File(new URI(loc)), false)) {
                Manifest mf = jf.getManifest();
                if (mf != null) {
                    if (isPluginManifest(mf)) {
                        LOGGER.log(Level.FINE, "{0} seems to be a Jenkins plugin, OK", loc);
                        return true;
                    } else {
                        LOGGER.log(Level.FINE, "{0} does not look like a Jenkins plugin", loc);
                    }
                } else {
                    LOGGER.log(Level.FINE, "ignoring {0} with no manifest", loc);
                }
            } catch (Exception x) {
                LOGGER.log(Level.WARNING, "problem checking " + loc, x);
            }
        }
        Matcher m = CLASSES_JAR.matcher(loc);
        if (m.matches()) {
            // Cf. ClassicPluginStrategy.createClassJarFromWebInfClasses: handle legacy plugin format with unpacked WEB-INF/classes/
            try {
                File manifestFile = new File(new URI(m.group(1) + "META-INF/MANIFEST.MF"));
                if (manifestFile.isFile()) {
                    try (InputStream is = new FileInputStream(manifestFile)) {
                        if (isPluginManifest(new Manifest(is))) {
                            LOGGER.log(Level.FINE, "{0} looks like a Jenkins plugin based on {1}, OK",
                                    new Object[] { loc, manifestFile });
                            return true;
                        } else {
                            LOGGER.log(Level.FINE, "{0} does not look like a Jenkins plugin", manifestFile);
                        }
                    }
                } else {
                    LOGGER.log(Level.FINE, "{0} has no matching {1}", new Object[] { loc, manifestFile });
                }
            } catch (Exception x) {
                LOGGER.log(Level.WARNING, "problem checking " + loc, x);
            }
        }
        if (loc.endsWith("/target/classes/") || loc.matches(".+/build/classes/[^/]+/main/")) {
            LOGGER.log(Level.FINE, "{0} seems to be current plugin classes, OK", loc);
            return true;
        }
        if (Main.isUnitTest) {
            if (loc.endsWith("/target/test-classes/") || loc.endsWith("-tests.jar")
                    || loc.matches(".+/build/classes/[^/]+/test/")) {
                LOGGER.log(Level.FINE, "{0} seems to be test classes, OK", loc);
                return true;
            }
            if (loc.matches(".+/jenkins-test-harness-.+[.]jar")) {
                LOGGER.log(Level.FINE, "{0} seems to be jenkins-test-harness, OK", loc);
                return true;
            }
        }
        LOGGER.log(Level.FINE, "{0} is not recognized; rejecting", loc);
        return false;
    });
}

From source file:com.izforge.izpack.util.SelfModifier.java

/**
 * @throws IOException if an error occured
 *//*ww  w .  j a  v a 2s.c om*/
private void extractJarFile() throws IOException {
    int extracted = 0;
    InputStream in = null;
    String MANIFEST = "META-INF/MANIFEST.MF";
    JarFile jar = new JarFile(jarFile, true);

    try {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            if (entry.isDirectory()) {
                continue;
            }

            String pathname = entry.getName();
            if (MANIFEST.equals(pathname.toUpperCase())) {
                continue;
            }

            in = jar.getInputStream(entry);
            FileUtils.copyToFile(in, new File(sandbox, pathname));

            extracted++;
        }
        log("Extracted " + extracted + " file" + (extracted > 1 ? "s" : "") + " into " + sandbox.getPath());
    } finally {
        try {
            jar.close();
        } catch (IOException ignore) {
        }
        IOUtils.closeQuietly(in);
    }
}