8231093: Document the ZIP FS properties noCompression and releaseVersion
Reviewed-by: clanger, martin, alanb
This commit is contained in:
parent
3e47bb2c2e
commit
515db21790
@ -233,7 +233,7 @@ public class Locations {
|
||||
}
|
||||
|
||||
public void setMultiReleaseValue(String multiReleaseValue) {
|
||||
fsEnv = Collections.singletonMap("multi-release", multiReleaseValue);
|
||||
fsEnv = Collections.singletonMap("releaseVersion", multiReleaseValue);
|
||||
}
|
||||
|
||||
private boolean contains(Collection<Path> searchPath, Path file) throws IOException {
|
||||
|
@ -60,18 +60,20 @@ class JarFileSystem extends ZipFileSystem {
|
||||
|
||||
JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String,?> env) throws IOException {
|
||||
super(provider, zfpath, env);
|
||||
if (isMultiReleaseJar()) {
|
||||
Object o = getRuntimeVersion(env);
|
||||
if (isMultiReleaseJar() && (o != null)) {
|
||||
int version;
|
||||
Object o = env.get("multi-release");
|
||||
if (o instanceof String) {
|
||||
String s = (String)o;
|
||||
if (s.equals("runtime")) {
|
||||
version = Runtime.version().feature();
|
||||
} else if (s.matches("^[1-9][0-9]*$")) {
|
||||
version = Version.parse(s).feature();
|
||||
} else {
|
||||
version = Integer.parseInt(s);
|
||||
throw new IllegalArgumentException("Invalid runtime version");
|
||||
}
|
||||
} else if (o instanceof Integer) {
|
||||
version = (Integer)o;
|
||||
version = Version.parse(((Integer)o).toString()).feature();
|
||||
} else if (o instanceof Version) {
|
||||
version = ((Version)o).feature();
|
||||
} else {
|
||||
@ -83,6 +85,23 @@ class JarFileSystem extends ZipFileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to get the release version for a multi-release JAR. It
|
||||
* first checks the documented property {@code releaseVersion} and if not
|
||||
* found checks the original property {@code multi-release}
|
||||
* @param env ZIP FS map
|
||||
* @return release version or null if it is not specified
|
||||
*/
|
||||
private Object getRuntimeVersion(Map<String, ?> env) {
|
||||
Object o = null;
|
||||
if (env.containsKey(ZipFileSystemProvider.PROPERTY_RELEASE_VERSION)) {
|
||||
o = env.get(ZipFileSystemProvider.PROPERTY_RELEASE_VERSION);
|
||||
} else {
|
||||
o = env.get(ZipFileSystemProvider.PROPERTY_MULTI_RELEASE);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
private boolean isMultiReleaseJar() throws IOException {
|
||||
try (InputStream is = newInputStream(getBytes("/META-INF/MANIFEST.MF"))) {
|
||||
String multiRelease = new Manifest(is).getMainAttributes()
|
||||
|
@ -81,13 +81,19 @@ class ZipFileSystem extends FileSystem {
|
||||
(PrivilegedAction<Boolean>)()->System.getProperty("os.name")
|
||||
.startsWith("Windows"));
|
||||
private static final byte[] ROOTPATH = new byte[] { '/' };
|
||||
private static final String OPT_POSIX = "enablePosixFileAttributes";
|
||||
private static final String OPT_DEFAULT_OWNER = "defaultOwner";
|
||||
private static final String OPT_DEFAULT_GROUP = "defaultGroup";
|
||||
private static final String OPT_DEFAULT_PERMISSIONS = "defaultPermissions";
|
||||
private static final String PROPERTY_POSIX = "enablePosixFileAttributes";
|
||||
private static final String PROPERTY_DEFAULT_OWNER = "defaultOwner";
|
||||
private static final String PROPERTY_DEFAULT_GROUP = "defaultGroup";
|
||||
private static final String PROPERTY_DEFAULT_PERMISSIONS = "defaultPermissions";
|
||||
|
||||
private static final Set<PosixFilePermission> DEFAULT_PERMISSIONS =
|
||||
PosixFilePermissions.fromString("rwxrwxrwx");
|
||||
// Property used to specify the compression mode to use
|
||||
private static final String PROPERTY_COMPRESSION_METHOD = "compressionMethod";
|
||||
// Value specified for compressionMethod property to compress Zip entries
|
||||
private static final String COMPRESSION_METHOD_DEFLATED = "DEFLATED";
|
||||
// Value specified for compressionMethod property to not compress Zip entries
|
||||
private static final String COMPRESSION_METHOD_STORED = "STORED";
|
||||
|
||||
private final ZipFileSystemProvider provider;
|
||||
private final Path zfpath;
|
||||
@ -124,8 +130,8 @@ class ZipFileSystem extends FileSystem {
|
||||
this.noExtt = "false".equals(env.get("zipinfo-time"));
|
||||
this.useTempFile = isTrue(env, "useTempFile");
|
||||
this.forceEnd64 = isTrue(env, "forceZIP64End");
|
||||
this.defaultCompressionMethod = isTrue(env, "noCompression") ? METHOD_STORED : METHOD_DEFLATED;
|
||||
this.supportPosix = isTrue(env, OPT_POSIX);
|
||||
this.defaultCompressionMethod = getDefaultCompressionMethod(env);
|
||||
this.supportPosix = isTrue(env, PROPERTY_POSIX);
|
||||
this.defaultOwner = initOwner(zfpath, env);
|
||||
this.defaultGroup = initGroup(zfpath, env);
|
||||
this.defaultPermissions = initPermissions(env);
|
||||
@ -163,6 +169,50 @@ class ZipFileSystem extends FileSystem {
|
||||
this.zfpath = zfpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the compression method to use (STORED or DEFLATED). If the
|
||||
* property {@code commpressionMethod} is set use its value to determine
|
||||
* the compression method to use. If the property is not set, then the
|
||||
* default compression is DEFLATED unless the property {@code noCompression}
|
||||
* is set which is supported for backwards compatibility.
|
||||
* @param env Zip FS map of properties
|
||||
* @return The Compression method to use
|
||||
*/
|
||||
private int getDefaultCompressionMethod(Map<String, ?> env) {
|
||||
int result =
|
||||
isTrue(env, "noCompression") ? METHOD_STORED : METHOD_DEFLATED;
|
||||
if (env.containsKey(PROPERTY_COMPRESSION_METHOD)) {
|
||||
Object compressionMethod = env.get(PROPERTY_COMPRESSION_METHOD);
|
||||
if (compressionMethod != null) {
|
||||
if (compressionMethod instanceof String) {
|
||||
switch (((String) compressionMethod).toUpperCase()) {
|
||||
case COMPRESSION_METHOD_STORED:
|
||||
result = METHOD_STORED;
|
||||
break;
|
||||
case COMPRESSION_METHOD_DEFLATED:
|
||||
result = METHOD_DEFLATED;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The value for the %s property must be %s or %s",
|
||||
PROPERTY_COMPRESSION_METHOD, COMPRESSION_METHOD_STORED,
|
||||
COMPRESSION_METHOD_DEFLATED));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The Object type for the %s property must be a String",
|
||||
PROPERTY_COMPRESSION_METHOD));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The value for the %s property must be %s or %s",
|
||||
PROPERTY_COMPRESSION_METHOD, COMPRESSION_METHOD_STORED,
|
||||
COMPRESSION_METHOD_DEFLATED));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns true if there is a name=true/"true" setting in env
|
||||
private static boolean isTrue(Map<String, ?> env, String name) {
|
||||
return "true".equals(env.get(name)) || TRUE.equals(env.get(name));
|
||||
@ -173,7 +223,7 @@ class ZipFileSystem extends FileSystem {
|
||||
// be determined, we try to go with system property "user.name". If that's not
|
||||
// accessible, we return "<zipfs_default>".
|
||||
private UserPrincipal initOwner(Path zfpath, Map<String, ?> env) throws IOException {
|
||||
Object o = env.get(OPT_DEFAULT_OWNER);
|
||||
Object o = env.get(PROPERTY_DEFAULT_OWNER);
|
||||
if (o == null) {
|
||||
try {
|
||||
PrivilegedExceptionAction<UserPrincipal> pa = ()->Files.getOwner(zfpath);
|
||||
@ -193,7 +243,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (o instanceof String) {
|
||||
if (((String)o).isEmpty()) {
|
||||
throw new IllegalArgumentException("Value for property " +
|
||||
OPT_DEFAULT_OWNER + " must not be empty.");
|
||||
PROPERTY_DEFAULT_OWNER + " must not be empty.");
|
||||
}
|
||||
return ()->(String)o;
|
||||
}
|
||||
@ -201,7 +251,7 @@ class ZipFileSystem extends FileSystem {
|
||||
return (UserPrincipal)o;
|
||||
}
|
||||
throw new IllegalArgumentException("Value for property " +
|
||||
OPT_DEFAULT_OWNER + " must be of type " + String.class +
|
||||
PROPERTY_DEFAULT_OWNER + " must be of type " + String.class +
|
||||
" or " + UserPrincipal.class);
|
||||
}
|
||||
|
||||
@ -210,7 +260,7 @@ class ZipFileSystem extends FileSystem {
|
||||
// If this is not possible/unsupported, we will return a group principal going by
|
||||
// the same name as the default owner.
|
||||
private GroupPrincipal initGroup(Path zfpath, Map<String, ?> env) throws IOException {
|
||||
Object o = env.get(OPT_DEFAULT_GROUP);
|
||||
Object o = env.get(PROPERTY_DEFAULT_GROUP);
|
||||
if (o == null) {
|
||||
try {
|
||||
PosixFileAttributeView zfpv = Files.getFileAttributeView(zfpath, PosixFileAttributeView.class);
|
||||
@ -232,7 +282,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (o instanceof String) {
|
||||
if (((String)o).isEmpty()) {
|
||||
throw new IllegalArgumentException("Value for property " +
|
||||
OPT_DEFAULT_GROUP + " must not be empty.");
|
||||
PROPERTY_DEFAULT_GROUP + " must not be empty.");
|
||||
}
|
||||
return ()->(String)o;
|
||||
}
|
||||
@ -240,14 +290,14 @@ class ZipFileSystem extends FileSystem {
|
||||
return (GroupPrincipal)o;
|
||||
}
|
||||
throw new IllegalArgumentException("Value for property " +
|
||||
OPT_DEFAULT_GROUP + " must be of type " + String.class +
|
||||
PROPERTY_DEFAULT_GROUP + " must be of type " + String.class +
|
||||
" or " + GroupPrincipal.class);
|
||||
}
|
||||
|
||||
// Initialize the default permissions for files inside the zip archive.
|
||||
// If not specified in env, it will return 777.
|
||||
private Set<PosixFilePermission> initPermissions(Map<String, ?> env) {
|
||||
Object o = env.get(OPT_DEFAULT_PERMISSIONS);
|
||||
Object o = env.get(PROPERTY_DEFAULT_PERMISSIONS);
|
||||
if (o == null) {
|
||||
return DEFAULT_PERMISSIONS;
|
||||
}
|
||||
@ -256,7 +306,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
if (!(o instanceof Set)) {
|
||||
throw new IllegalArgumentException("Value for property " +
|
||||
OPT_DEFAULT_PERMISSIONS + " must be of type " + String.class +
|
||||
PROPERTY_DEFAULT_PERMISSIONS + " must be of type " + String.class +
|
||||
" or " + Set.class);
|
||||
}
|
||||
Set<PosixFilePermission> perms = new HashSet<>();
|
||||
@ -264,7 +314,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (o2 instanceof PosixFilePermission) {
|
||||
perms.add((PosixFilePermission)o2);
|
||||
} else {
|
||||
throw new IllegalArgumentException(OPT_DEFAULT_PERMISSIONS +
|
||||
throw new IllegalArgumentException(PROPERTY_DEFAULT_PERMISSIONS +
|
||||
" must only contain objects of type " + PosixFilePermission.class);
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,11 @@ import java.util.zip.ZipException;
|
||||
*/
|
||||
public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
|
||||
// Property used to specify the entry version to use for a multi-release JAR
|
||||
static final String PROPERTY_RELEASE_VERSION = "releaseVersion";
|
||||
// Original property used to specify the entry version to use for a
|
||||
// multi-release JAR which is kept for backwards compatibility.
|
||||
static final String PROPERTY_MULTI_RELEASE = "multi-release";
|
||||
private final Map<Path, ZipFileSystem> filesystems = new HashMap<>();
|
||||
|
||||
public ZipFileSystemProvider() {}
|
||||
@ -104,20 +109,7 @@ public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
if (filesystems.containsKey(realPath))
|
||||
throw new FileSystemAlreadyExistsException();
|
||||
}
|
||||
ZipFileSystem zipfs;
|
||||
try {
|
||||
if (env.containsKey("multi-release")) {
|
||||
zipfs = new JarFileSystem(this, path, env);
|
||||
} else {
|
||||
zipfs = new ZipFileSystem(this, path, env);
|
||||
}
|
||||
} catch (ZipException ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
// assume NOT a zip/jar file
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
ZipFileSystem zipfs = getZipFileSystem(path, env);
|
||||
if (realPath == null) { // newly created
|
||||
realPath = path.toRealPath();
|
||||
}
|
||||
@ -131,20 +123,25 @@ public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
throws IOException
|
||||
{
|
||||
ensureFile(path);
|
||||
return getZipFileSystem(path, env);
|
||||
}
|
||||
|
||||
private ZipFileSystem getZipFileSystem(Path path, Map<String, ?> env) throws IOException {
|
||||
ZipFileSystem zipfs;
|
||||
try {
|
||||
ZipFileSystem zipfs;
|
||||
if (env.containsKey("multi-release")) {
|
||||
if (env.containsKey(PROPERTY_RELEASE_VERSION) ||
|
||||
env.containsKey(PROPERTY_MULTI_RELEASE)) {
|
||||
zipfs = new JarFileSystem(this, path, env);
|
||||
} else {
|
||||
zipfs = new ZipFileSystem(this, path, env);
|
||||
}
|
||||
return zipfs;
|
||||
} catch (ZipException ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return zipfs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,7 +147,7 @@ import java.util.Set;
|
||||
* <tbody>
|
||||
* <tr>
|
||||
* <th scope="row">create</th>
|
||||
* <td>java.lang.String</td>
|
||||
* <td>{@link java.lang.String} or {@link java.lang.Boolean}</td>
|
||||
* <td>false</td>
|
||||
* <td>
|
||||
* If the value is {@code true}, the Zip file system provider
|
||||
@ -156,7 +156,7 @@ import java.util.Set;
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">encoding</th>
|
||||
* <td>java.lang.String</td>
|
||||
* <td>{@link java.lang.String}</td>
|
||||
* <td>UTF-8</td>
|
||||
* <td>
|
||||
* The value indicates the encoding scheme for the
|
||||
@ -164,8 +164,8 @@ import java.util.Set;
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td scope="row">enablePosixFileAttributes</td>
|
||||
* <td>java.lang.String</td>
|
||||
* <th scope="row">enablePosixFileAttributes</th>
|
||||
* <td>{@link java.lang.String} or {@link java.lang.Boolean}</td>
|
||||
* <td>false</td>
|
||||
* <td>
|
||||
* If the value is {@code true}, the Zip file system will support
|
||||
@ -173,8 +173,9 @@ import java.util.Set;
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td scope="row">defaultOwner</td>
|
||||
* <td>{@link java.nio.file.attribute.UserPrincipal UserPrincipal}<br> or java.lang.String</td>
|
||||
* <th scope="row">defaultOwner</th>
|
||||
* <td>{@link java.nio.file.attribute.UserPrincipal UserPrincipal}<br> or
|
||||
* {@link java.lang.String}</td>
|
||||
* <td>null/unset</td>
|
||||
* <td>
|
||||
* Override the default owner for entries in the Zip file system.<br>
|
||||
@ -182,8 +183,9 @@ import java.util.Set;
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td scope="row">defaultGroup</td>
|
||||
* <td>{@link java.nio.file.attribute.GroupPrincipal GroupPrincipal}<br> or java.lang.String</td>
|
||||
* <th scope="row">defaultGroup</th>
|
||||
* <td>{@link java.nio.file.attribute.GroupPrincipal GroupPrincipal}<br> or
|
||||
* {@link java.lang.String}</td>
|
||||
* <td>null/unset</td>
|
||||
* <td>
|
||||
* Override the the default group for entries in the Zip file system.<br>
|
||||
@ -191,9 +193,9 @@ import java.util.Set;
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td scope="row">defaultPermissions</td>
|
||||
* <th scope="row">defaultPermissions</th>
|
||||
* <td>{@link java.util.Set Set}<{@link java.nio.file.attribute.PosixFilePermission PosixFilePermission}><br>
|
||||
* or java.lang.String</td>
|
||||
* or {@link java.lang.String}</td>
|
||||
* <td>null/unset</td>
|
||||
* <td>
|
||||
* Override the default Set of permissions for entries in the Zip file system.<br>
|
||||
@ -201,7 +203,66 @@ import java.util.Set;
|
||||
* a String that is parsed by {@link java.nio.file.attribute.PosixFilePermissions#fromString PosixFilePermissions::fromString}
|
||||
* </td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* <tr>
|
||||
* <th scope="row">compressionMethod</th>
|
||||
* <td>{@link java.lang.String}</td>
|
||||
* <td>"DEFLATED"</td>
|
||||
* <td>
|
||||
* The value representing the compression method to use when writing entries
|
||||
* to the Zip file system.
|
||||
* <ul>
|
||||
* <li>
|
||||
* If the value is {@code "STORED"}, the Zip file system provider will
|
||||
* not compress entries when writing to the Zip file system.
|
||||
* </li>
|
||||
* <li>
|
||||
* If the value is {@code "DEFLATED"} or the property is not set,
|
||||
* the Zip file system provider will use data compression when
|
||||
* writing entries to the Zip file system.
|
||||
* </li>
|
||||
* <li>
|
||||
* If the value is not {@code "STORED"} or {@code "DEFLATED"}, an
|
||||
* {@code IllegalArgumentException} will be thrown when the Zip
|
||||
* filesystem is created.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">releaseVersion</th>
|
||||
* <td>{@link java.lang.String} or {@link java.lang.Integer}</td>
|
||||
* <td>null/unset</td>
|
||||
* <td>
|
||||
* A value representing the version entry to use when accessing a
|
||||
* <a href=="{@docRoot}/../specs/jar/jar.html#multi-release-jar-files">
|
||||
* multi-release JAR</a>. If the JAR is not a
|
||||
* <a href=="{@docRoot}/../specs/jar/jar.html#multi-release-jar-files">
|
||||
* multi-release JAR</a>, the value will be ignored and the JAR will be
|
||||
* considered un-versioned.
|
||||
* <p>
|
||||
* The value must be either the string "runtime" or represent a valid
|
||||
* {@linkplain Runtime.Version Java SE Platform version number},
|
||||
* such as {@code 9} or {@code 14}, in order to determine the version entry.
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* If the value is {@code null} or the property is not set,
|
||||
* then the JAR will be treated as an un-versioned JAR.
|
||||
* </li>
|
||||
* <li>
|
||||
* If the value is {@code "runtime"}, the
|
||||
* version entry will be determined by invoking
|
||||
* {@linkplain Runtime.Version#feature() Runtime.Version.feature()}.
|
||||
* </li>
|
||||
* <li>
|
||||
* If the value does not represent a valid
|
||||
* {@linkplain Runtime.Version Java SE Platform version number},
|
||||
* an {@code IllegalArgumentException} will be thrown.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
*
|
||||
* <h2>Examples:</h2>
|
||||
@ -223,7 +284,7 @@ import java.util.Set;
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* FileSystem zipfs = FileSystems.newFileSystem(Path.of("helloworld.jar"), null);
|
||||
* FileSystem zipfs = FileSystems.newFileSystem(Path.of("helloworld.jar"));
|
||||
* Path rootDir = zipfs.getPath("/");
|
||||
* Files.walk(rootDir)
|
||||
* .forEach(System.out::println);
|
||||
|
253
test/jdk/jdk/nio/zipfs/CompressionModeTest.java
Normal file
253
test/jdk/jdk/nio/zipfs/CompressionModeTest.java
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code 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 General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8231093
|
||||
* @summary Test Zip FS compressionMethod property
|
||||
* @modules jdk.zipfs
|
||||
* @run testng CompressionModeTest
|
||||
*/
|
||||
public class CompressionModeTest {
|
||||
|
||||
private static final Path HERE = Path.of(".");
|
||||
|
||||
/**
|
||||
* Number of ZIP entries to create
|
||||
*/
|
||||
private static final int ENTRIES = 5;
|
||||
|
||||
/**
|
||||
* Value used for creating the required entries in a ZIP or JAR file
|
||||
*/
|
||||
private static final String ZIP_FILE_VALUE = "US Open 2019";
|
||||
private static final byte[] ZIP_FILE_ENTRY =
|
||||
ZIP_FILE_VALUE.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
private static final SecureRandom random = new SecureRandom();
|
||||
|
||||
/**
|
||||
* Validate that you can create a ZIP file with and without compression
|
||||
* and that entries are created with the specified compression method.
|
||||
*
|
||||
* @param env Properties used for creating the ZIP Filesystem
|
||||
* @param compression Indicates whether the files are DEFLATED(default)
|
||||
* or STORED
|
||||
* @throws Exception If an error occurs during the creation, verification or
|
||||
* deletion of the ZIP file
|
||||
*/
|
||||
@Test(dataProvider = "validCompressionMethods", enabled = true)
|
||||
public void testValidCompressionMehods(Map<String, String> env,
|
||||
int compression) throws Exception {
|
||||
|
||||
System.out.printf("ZIP FS Map = %s, Compression mode= %s%n ",
|
||||
formatMap(env), compression);
|
||||
|
||||
Path zipfile = generatePath(HERE, "test", ".zip");
|
||||
Files.deleteIfExists(zipfile);
|
||||
createZipFile(zipfile, env, ENTRIES);
|
||||
verify(zipfile, compression, ENTRIES, 0);
|
||||
Files.deleteIfExists(zipfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an IllegalArgumentException is thrown when an invalid
|
||||
* value is specified for the compressionMethod property.
|
||||
*
|
||||
* @param env Properties used for creating the ZIP Filesystem
|
||||
* @throws Exception if an error occurs other than the expected
|
||||
* IllegalArgumentException
|
||||
*/
|
||||
@Test(dataProvider = "invalidCompressionMethod")
|
||||
public void testInvalidCompressionMethod(Map<String, String> env) throws Exception {
|
||||
System.out.printf("ZIP FS Map = %s%n ", formatMap(env));
|
||||
Path zipfile = generatePath(HERE, "test", ".zip");
|
||||
Files.deleteIfExists(zipfile);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
createZipFile(zipfile, env, ENTRIES));
|
||||
Files.deleteIfExists(zipfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP File System using the specified properties and a ZIP file
|
||||
* with the specified number of entries
|
||||
*
|
||||
* @param zipFile Path to the ZIP File to create
|
||||
* @param env Properties used for creating the ZIP Filesystem
|
||||
* @param entries Number of entries to add to the ZIP File
|
||||
* @throws IOException If an error occurs while creating the ZIP file
|
||||
*/
|
||||
private void createZipFile(Path zipFile, Map<String, String> env,
|
||||
int entries) throws IOException {
|
||||
System.out.printf("Creating file = %s%n", zipFile);
|
||||
try (FileSystem zipfs =
|
||||
FileSystems.newFileSystem(zipFile, env)) {
|
||||
|
||||
for (int i = 0; i < entries; i++) {
|
||||
Files.writeString(zipfs.getPath("Entry-" + i), ZIP_FILE_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider used to validate that you can create a ZIP file with and
|
||||
* without compression.
|
||||
*/
|
||||
@DataProvider(name = "validCompressionMethods")
|
||||
private Object[][] validCompressionMethods() {
|
||||
return new Object[][]{
|
||||
{Map.of("create", "true"), ZipEntry.DEFLATED},
|
||||
{Map.of("create", "true", "noCompression", "true"),
|
||||
ZipEntry.STORED},
|
||||
{Map.of("create", "true", "noCompression", "false"),
|
||||
ZipEntry.DEFLATED},
|
||||
{Map.of("create", "true", "compressionMethod", "STORED"),
|
||||
ZipEntry.STORED},
|
||||
{Map.of("create", "true", "compressionMethod", "DEFLATED"),
|
||||
ZipEntry.DEFLATED},
|
||||
{Map.of("create", "true", "compressionMethod", "stored"),
|
||||
ZipEntry.STORED},
|
||||
{Map.of("create", "true", "compressionMethod", "deflated"),
|
||||
ZipEntry.DEFLATED}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider used to validate that an IllegalArgumentException is thrown
|
||||
* for an invalid value for the compressionMethod property.
|
||||
*/
|
||||
@DataProvider(name = "invalidCompressionMethod")
|
||||
private Object[][] invalidCompressionMethod() {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
map.put("create", "true");
|
||||
map.put("compressionMethod", null);
|
||||
return new Object[][]{
|
||||
{map},
|
||||
{Map.of("create", "true", "compressionMethod", "")},
|
||||
{Map.of("create", "true", "compressionMethod",
|
||||
Integer.parseInt("5"))},
|
||||
{Map.of("create", "true", "compressionMethod", "invalid")}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the given path is a ZIP file containing the
|
||||
* expected entries.
|
||||
*
|
||||
* @param zipfile ZIP file to be validated
|
||||
* @param method Expected Compression method: STORED or DEFLATED
|
||||
* @param entries Number of expected entries
|
||||
* @param start Starting number for verifying entries
|
||||
* @throws Exception If an error occurs while examining the ZIP file
|
||||
*/
|
||||
private static void verify(Path zipfile, int method, int entries,
|
||||
int start) throws Exception {
|
||||
// check entries with ZIP API
|
||||
try (ZipFile zf = new ZipFile(zipfile.toFile())) {
|
||||
// check entry count
|
||||
assertEquals(entries, zf.size());
|
||||
|
||||
// check compression method and content of each entry
|
||||
for (int i = start; i < entries; i++) {
|
||||
ZipEntry ze = zf.getEntry("Entry-" + i);
|
||||
assertNotNull(ze);
|
||||
assertEquals(method, ze.getMethod());
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY));
|
||||
}
|
||||
}
|
||||
}
|
||||
// check entries with FileSystem API
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zipfile)) {
|
||||
|
||||
// check entry count
|
||||
Path top = fs.getPath("/");
|
||||
long count = Files.find(top, Integer.MAX_VALUE, (path, attrs) ->
|
||||
attrs.isRegularFile() || (attrs.isDirectory() &&
|
||||
path.getFileName() != null &&
|
||||
path.getFileName().toString().equals("META-INF")))
|
||||
.count();
|
||||
assertEquals(entries, count);
|
||||
|
||||
// check content of each entry
|
||||
for (int i = start; i < entries; i++) {
|
||||
Path file = fs.getPath("Entry-" + i);
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a temporary file Path
|
||||
*
|
||||
* @param dir Directory used to create the path
|
||||
* @param prefix The prefix string used to create the path
|
||||
* @param suffix The suffix string used to create the path
|
||||
* @return Path that was generated
|
||||
*/
|
||||
private static Path generatePath(Path dir, String prefix, String suffix) {
|
||||
long n = random.nextLong();
|
||||
String s = prefix + Long.toUnsignedString(n) + suffix;
|
||||
Path name = dir.getFileSystem().getPath(s);
|
||||
// the generated name should be a simple file name
|
||||
if (name.getParent() != null)
|
||||
throw new IllegalArgumentException("Invalid prefix or suffix");
|
||||
return dir.resolve(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to return a formatted String of the key:value entries for
|
||||
* a Map
|
||||
*
|
||||
* @param env Map to format
|
||||
* @return Formatted string of the Map entries
|
||||
*/
|
||||
private static String formatMap(Map<String, String> env) {
|
||||
return env.entrySet().stream()
|
||||
.map(e -> format("(%s:%s)", e.getKey(), e.getValue()))
|
||||
.collect(joining(", "));
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8144355 8144062 8176709 8194070 8193802
|
||||
* @bug 8144355 8144062 8176709 8194070 8193802 8231093
|
||||
* @summary Test aliasing additions to ZipFileSystem for multi-release jar files
|
||||
* @library /lib/testlibrary/java/util/jar
|
||||
* @modules jdk.compiler
|
||||
@ -40,6 +40,7 @@ import java.lang.invoke.MethodType;
|
||||
import java.lang.Runtime.Version;
|
||||
import java.net.URI;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@ -88,8 +89,7 @@ public class MultiReleaseJarTest {
|
||||
public Object[][] createStrings() {
|
||||
return new Object[][]{
|
||||
{"runtime", MAJOR_VERSION},
|
||||
{"-20", 8},
|
||||
{"0", 8},
|
||||
{null, 8},
|
||||
{"8", 8},
|
||||
{"9", 9},
|
||||
{Integer.toString(MAJOR_VERSION), MAJOR_VERSION},
|
||||
@ -101,8 +101,7 @@ public class MultiReleaseJarTest {
|
||||
@DataProvider(name="integers")
|
||||
public Object[][] createIntegers() {
|
||||
return new Object[][] {
|
||||
{Integer.valueOf(-5), 8},
|
||||
{Integer.valueOf(0), 8},
|
||||
{null, 8},
|
||||
{Integer.valueOf(8), 8},
|
||||
{Integer.valueOf(9), 9},
|
||||
{Integer.valueOf(MAJOR_VERSION), MAJOR_VERSION},
|
||||
@ -114,6 +113,7 @@ public class MultiReleaseJarTest {
|
||||
@DataProvider(name="versions")
|
||||
public Object[][] createVersions() {
|
||||
return new Object[][] {
|
||||
{null, 8},
|
||||
{Version.parse("8"), 8},
|
||||
{Version.parse("9"), 9},
|
||||
{Version.parse(Integer.toString(MAJOR_VERSION)), MAJOR_VERSION},
|
||||
@ -122,6 +122,20 @@ public class MultiReleaseJarTest {
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider(name="invalidVersions")
|
||||
public Object[][] invalidVersions() {
|
||||
return new Object[][] {
|
||||
{Map.of("releaseVersion", "")},
|
||||
{Map.of("releaseVersion", "invalid")},
|
||||
{Map.of("releaseVersion", "0")},
|
||||
{Map.of("releaseVersion", "-1")},
|
||||
{Map.of("releaseVersion", "11.0.1")},
|
||||
{Map.of("releaseVersion", new ArrayList<Long>())},
|
||||
{Map.of("releaseVersion", Integer.valueOf(0))},
|
||||
{Map.of("releaseVersion", Integer.valueOf(-1))}
|
||||
};
|
||||
}
|
||||
|
||||
// Not the best test but all I can do since ZipFileSystem and JarFileSystem
|
||||
// are not public, so I can't use (fs instanceof ...)
|
||||
@Test
|
||||
@ -131,7 +145,7 @@ public class MultiReleaseJarTest {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
|
||||
Assert.assertTrue(readAndCompare(fs, 8));
|
||||
}
|
||||
env.put("multi-release", "runtime");
|
||||
env.put("releaseVersion", "runtime");
|
||||
// a configuration and jar file is multi-release
|
||||
try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
|
||||
Assert.assertTrue(readAndCompare(fs, MAJOR_VERSION));
|
||||
@ -150,30 +164,67 @@ public class MultiReleaseJarTest {
|
||||
|
||||
@Test(dataProvider="strings")
|
||||
public void testStrings(String value, int expected) throws Throwable {
|
||||
stringEnv.put("multi-release", value);
|
||||
stringEnv.put("releaseVersion", value);
|
||||
runTest(stringEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="integers")
|
||||
public void testIntegers(Integer value, int expected) throws Throwable {
|
||||
integerEnv.put("multi-release", value);
|
||||
integerEnv.put("releaseVersion", value);
|
||||
runTest(integerEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="versions")
|
||||
public void testVersions(Version value, int expected) throws Throwable {
|
||||
versionEnv.put("multi-release", value);
|
||||
versionEnv.put("releaseVersion", value);
|
||||
runTest(versionEnv, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortJar() throws Throwable {
|
||||
integerEnv.put("multi-release", Integer.valueOf(MAJOR_VERSION));
|
||||
integerEnv.put("releaseVersion", Integer.valueOf(MAJOR_VERSION));
|
||||
runTest(smruri, integerEnv, MAJOR_VERSION);
|
||||
integerEnv.put("multi-release", Integer.valueOf(9));
|
||||
integerEnv.put("releaseVersion", Integer.valueOf(9));
|
||||
runTest(smruri, integerEnv, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an invalid value for the "releaseVersion" property throws
|
||||
* an {@code IllegalArgumentException}
|
||||
* @param env Zip FS map
|
||||
* @throws Throwable Exception thrown for anything other than the expected
|
||||
* IllegalArgumentException
|
||||
*/
|
||||
@Test(dataProvider="invalidVersions")
|
||||
public void testInvalidVersions(Map<String,?> env) throws Throwable {
|
||||
Assert.assertThrows(IllegalArgumentException.class, () ->
|
||||
FileSystems.newFileSystem(Path.of(userdir,
|
||||
"multi-release.jar"), env));
|
||||
}
|
||||
|
||||
// The following tests are for backwards compatibility to validate that
|
||||
// the original property still works
|
||||
@Test(dataProvider="strings")
|
||||
public void testMRStrings(String value, int expected) throws Throwable {
|
||||
stringEnv.clear();
|
||||
stringEnv.put("multi-release", value);
|
||||
runTest(stringEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="integers")
|
||||
public void testMRIntegers(Integer value, int expected) throws Throwable {
|
||||
integerEnv.clear();
|
||||
integerEnv.put("multi-release", value);
|
||||
runTest(integerEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="versions")
|
||||
public void testMRVersions(Version value, int expected) throws Throwable {
|
||||
versionEnv.clear();
|
||||
versionEnv.put("multi-release", value);
|
||||
runTest(versionEnv, expected);
|
||||
}
|
||||
|
||||
private void runTest(Map<String,?> env, int expected) throws Throwable {
|
||||
runTest(mruri, env, expected);
|
||||
}
|
||||
@ -213,7 +264,7 @@ public class MultiReleaseJarTest {
|
||||
JarBuilder jb = new JarBuilder(jfname);
|
||||
jb.addAttribute("Multi-Release", "true");
|
||||
jb.build();
|
||||
Map<String,String> env = Map.of("multi-release", "runtime");
|
||||
Map<String,String> env = Map.of("releaseVersion", "runtime");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
@ -228,7 +279,7 @@ public class MultiReleaseJarTest {
|
||||
creator.buildCustomMultiReleaseJar(fileName, value, Map.of(),
|
||||
/*addEntries*/true);
|
||||
|
||||
Map<String,String> env = Map.of("multi-release", "runtime");
|
||||
Map<String,String> env = Map.of("releaseVersion", "runtime");
|
||||
Path filePath = Paths.get(userdir, fileName);
|
||||
String ssp = filePath.toUri().toString();
|
||||
URI customJar = new URI("jar", ssp , null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user