1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jaxp.library; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.io.OutputStream; 28 import java.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.nio.file.StandardCopyOption; 32 import java.util.ArrayList; 33 import java.util.Enumeration; 34 import java.util.List; 35 import java.util.Set; 36 import java.util.jar.JarEntry; 37 import java.util.jar.JarFile; 38 import java.util.jar.JarOutputStream; 39 import java.util.jar.Manifest; 40 import java.util.stream.Collectors; 41 import java.util.stream.Stream; 42 43 /** 44 * This class consists exclusively of static utility methods that are useful 45 * for creating and manipulating JAR files. 46 */ 47 48 public final class JarUtils { 49 private JarUtils() { } 50 51 /** 52 * Creates a JAR file. 53 * 54 * Equivalent to {@code jar cfm <jarfile> <manifest> -C <dir> file...} 55 * 56 * The input files are resolved against the given directory. Any input 57 * files that are directories are processed recursively. 58 */ 59 public static void createJarFile(Path jarfile, Manifest man, Path dir, Path... file) 60 throws IOException 61 { 62 // create the target directory 63 Path parent = jarfile.getParent(); 64 if (parent != null) 65 Files.createDirectories(parent); 66 67 List<Path> entries = new ArrayList<>(); 68 for (Path entry : file) { 69 Files.find(dir.resolve(entry), Integer.MAX_VALUE, 70 (p, attrs) -> attrs.isRegularFile()) 71 .map(e -> dir.relativize(e)) 72 .forEach(entries::add); 73 } 74 75 try (OutputStream out = Files.newOutputStream(jarfile); 76 JarOutputStream jos = new JarOutputStream(out)) 77 { 78 if (man != null) { 79 JarEntry je = new JarEntry(JarFile.MANIFEST_NAME); 80 jos.putNextEntry(je); 81 man.write(jos); 82 jos.closeEntry(); 83 } 84 85 for (Path entry : entries) { 86 String name = toJarEntryName(entry); 87 jos.putNextEntry(new JarEntry(name)); 88 Files.copy(dir.resolve(entry), jos); 89 jos.closeEntry(); 90 } 91 } 92 } 93 94 /** 95 * Creates a JAR file. 96 * 97 * Equivalent to {@code jar cf <jarfile> -C <dir> file...} 98 * 99 * The input files are resolved against the given directory. Any input 100 * files that are directories are processed recursively. 101 */ 102 public static void createJarFile(Path jarfile, Path dir, Path... file) 103 throws IOException 104 { 105 createJarFile(jarfile, null, dir, file); 106 } 107 108 /** 109 * Creates a JAR file. 110 * 111 * Equivalent to {@code jar cf <jarfile> -C <dir> file...} 112 * 113 * The input files are resolved against the given directory. Any input 114 * files that are directories are processed recursively. 115 */ 116 public static void createJarFile(Path jarfile, Path dir, String... input) 117 throws IOException 118 { 119 Path[] paths = Stream.of(input).map(Paths::get).toArray(Path[]::new); 120 createJarFile(jarfile, dir, paths); 121 } 122 123 /** 124 * Creates a JAR file from the contents of a directory. 125 * 126 * Equivalent to {@code jar cf <jarfile> -C <dir> .} 127 */ 128 public static void createJarFile(Path jarfile, Path dir) throws IOException { 129 createJarFile(jarfile, dir, Paths.get(".")); 130 } 131 132 /** 133 * Map a file path to the equivalent name in a JAR file 134 */ 135 private static String toJarEntryName(Path file) { 136 Path normalized = file.normalize(); 137 return normalized.subpath(0, normalized.getNameCount()) // drop root 138 .toString() 139 .replace(File.separatorChar, '/'); 140 } 141 }