8234089: (zipfs) Remove classes JarFileSystemProvider and JarFileSystem
Reviewed-by: lancea, alanb
This commit is contained in:
parent
3600213f1d
commit
b240008ba2
@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.nio.zipfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.Runtime.Version;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* Adds aliasing to ZipFileSystem to support multi-release jar files. An alias map
|
||||
* is created by {@link JarFileSystem#createVersionedLinks(int)}. The map is then
|
||||
* consulted when an entry is looked up in {@link JarFileSystem#getInode(byte[])}
|
||||
* to determine if the entry has a corresponding versioned entry. If so, the
|
||||
* versioned entry is returned.
|
||||
*
|
||||
* @author Steve Drach
|
||||
*/
|
||||
class JarFileSystem extends ZipFileSystem {
|
||||
// lookup needs to be initialized because isMultiReleaseJar is called before createVersionedLinks
|
||||
private Function<byte[], byte[]> lookup = path -> path;
|
||||
|
||||
@Override
|
||||
IndexNode getInode(byte[] path) {
|
||||
// check for an alias to a versioned entry
|
||||
return super.getInode(lookup.apply(path));
|
||||
}
|
||||
|
||||
JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String,?> env) throws IOException {
|
||||
super(provider, zfpath, env);
|
||||
Object o = getRuntimeVersion(env);
|
||||
if (isMultiReleaseJar() && (o != null)) {
|
||||
int version;
|
||||
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 {
|
||||
throw new IllegalArgumentException("Invalid runtime version");
|
||||
}
|
||||
} else if (o instanceof Integer) {
|
||||
version = Version.parse(((Integer)o).toString()).feature();
|
||||
} else if (o instanceof Version) {
|
||||
version = ((Version)o).feature();
|
||||
} else {
|
||||
throw new IllegalArgumentException("env parameter must be String, Integer, "
|
||||
+ "or Version");
|
||||
}
|
||||
createVersionedLinks(version < 0 ? 0 : version);
|
||||
setReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
.getValue(Attributes.Name.MULTI_RELEASE);
|
||||
return "true".equalsIgnoreCase(multiRelease);
|
||||
} catch (NoSuchFileException x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a map of aliases for versioned entries, for example:
|
||||
* version/PackagePrivate.class -> META-INF/versions/9/version/PackagePrivate.class
|
||||
* version/PackagePrivate.java -> META-INF/versions/9/version/PackagePrivate.java
|
||||
* version/Version.class -> META-INF/versions/10/version/Version.class
|
||||
* version/Version.java -> META-INF/versions/10/version/Version.java
|
||||
*
|
||||
* then wrap the map in a function that getEntry can use to override root
|
||||
* entry lookup for entries that have corresponding versioned entries
|
||||
*/
|
||||
private void createVersionedLinks(int version) {
|
||||
IndexNode verdir = getInode(getBytes("/META-INF/versions"));
|
||||
// nothing to do, if no /META-INF/versions
|
||||
if (verdir == null) {
|
||||
return;
|
||||
}
|
||||
// otherwise, create a map and for each META-INF/versions/{n} directory
|
||||
// put all the leaf inodes, i.e. entries, into the alias map
|
||||
// possibly shadowing lower versioned entries
|
||||
HashMap<IndexNode, byte[]> aliasMap = new HashMap<>();
|
||||
getVersionMap(version, verdir).values().forEach(versionNode ->
|
||||
walk(versionNode.child, entryNode ->
|
||||
aliasMap.put(
|
||||
getOrCreateInode(getRootName(entryNode, versionNode), entryNode.isdir),
|
||||
entryNode.name))
|
||||
);
|
||||
lookup = path -> {
|
||||
byte[] entry = aliasMap.get(IndexNode.keyOf(path));
|
||||
return entry == null ? path : entry;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* create a sorted version map of version -> inode, for inodes <= max version
|
||||
* 9 -> META-INF/versions/9
|
||||
* 10 -> META-INF/versions/10
|
||||
*/
|
||||
private TreeMap<Integer, IndexNode> getVersionMap(int version, IndexNode metaInfVersions) {
|
||||
TreeMap<Integer,IndexNode> map = new TreeMap<>();
|
||||
IndexNode child = metaInfVersions.child;
|
||||
while (child != null) {
|
||||
Integer key = getVersion(child, metaInfVersions);
|
||||
if (key != null && key <= version) {
|
||||
map.put(key, child);
|
||||
}
|
||||
child = child.sibling;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* extract the integer version number -- META-INF/versions/9 returns 9
|
||||
*/
|
||||
private Integer getVersion(IndexNode inode, IndexNode metaInfVersions) {
|
||||
try {
|
||||
byte[] fullName = inode.name;
|
||||
return Integer.parseInt(getString(Arrays
|
||||
.copyOfRange(fullName, metaInfVersions.name.length + 1, fullName.length)));
|
||||
} catch (NumberFormatException x) {
|
||||
// ignore this even though it might indicate issues with the JAR structure
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* walk the IndexNode tree processing all leaf nodes
|
||||
*/
|
||||
private void walk(IndexNode inode, Consumer<IndexNode> consumer) {
|
||||
if (inode == null) return;
|
||||
if (inode.isDir()) {
|
||||
walk(inode.child, consumer);
|
||||
} else {
|
||||
consumer.accept(inode);
|
||||
}
|
||||
walk(inode.sibling, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* extract the root name from a versioned entry name
|
||||
* given inode for META-INF/versions/9/foo/bar.class
|
||||
* and prefix META-INF/versions/9/
|
||||
* returns foo/bar.class
|
||||
*/
|
||||
private byte[] getRootName(IndexNode inode, IndexNode prefix) {
|
||||
byte[] fullName = inode.name;
|
||||
return Arrays.copyOfRange(fullName, prefix.name.length, fullName.length);
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.nio.zipfs;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
class JarFileSystemProvider extends ZipFileSystemProvider {
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "jar";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path uriToPath(URI uri) {
|
||||
String scheme = uri.getScheme();
|
||||
if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
|
||||
throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
|
||||
}
|
||||
try {
|
||||
String uristr = uri.toString();
|
||||
int end = uristr.indexOf("!/");
|
||||
uristr = uristr.substring(4, (end == -1) ? uristr.length() : end);
|
||||
uri = new URI(uristr);
|
||||
return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
|
||||
.toAbsolutePath();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new AssertionError(e); //never thrown
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath(URI uri) {
|
||||
FileSystem fs = getFileSystem(uri);
|
||||
String path = uri.getFragment();
|
||||
if (path == null) {
|
||||
String uristr = uri.toString();
|
||||
int off = uristr.indexOf("!/");
|
||||
if (off != -1)
|
||||
path = uristr.substring(off + 2);
|
||||
}
|
||||
if (path != null)
|
||||
return fs.getPath(path);
|
||||
throw new IllegalArgumentException("URI: "
|
||||
+ uri
|
||||
+ " does not contain path fragment ex. jar:///c:/foo.zip!/BAR");
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.Runtime.Version;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
@ -50,6 +51,10 @@ import java.security.PrivilegedExceptionAction;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.Deflater;
|
||||
@ -85,6 +90,11 @@ class ZipFileSystem extends FileSystem {
|
||||
private static final String PROPERTY_DEFAULT_OWNER = "defaultOwner";
|
||||
private static final String PROPERTY_DEFAULT_GROUP = "defaultGroup";
|
||||
private static final String PROPERTY_DEFAULT_PERMISSIONS = "defaultPermissions";
|
||||
// Property used to specify the entry version to use for a multi-release JAR
|
||||
private 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.
|
||||
private static final String PROPERTY_MULTI_RELEASE = "multi-release";
|
||||
|
||||
private static final Set<PosixFilePermission> DEFAULT_PERMISSIONS =
|
||||
PosixFilePermissions.fromString("rwxrwxrwx");
|
||||
@ -112,6 +122,9 @@ class ZipFileSystem extends FileSystem {
|
||||
private final int defaultCompressionMethod; // METHOD_STORED if "noCompression=true"
|
||||
// METHOD_DEFLATED otherwise
|
||||
|
||||
// entryLookup is identity by default, will be overridden for multi-release jars
|
||||
private Function<byte[], byte[]> entryLookup = Function.identity();
|
||||
|
||||
// POSIX support
|
||||
final boolean supportPosix;
|
||||
private final UserPrincipal defaultOwner;
|
||||
@ -167,6 +180,8 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
this.provider = provider;
|
||||
this.zfpath = zfpath;
|
||||
|
||||
initializeReleaseVersion(env);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1349,6 +1364,142 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a version property has been specified and the file represents a multi-release JAR,
|
||||
* determine the requested runtime version and initialize the ZipFileSystem instance accordingly.
|
||||
*
|
||||
* Checks if the Zip File System property "releaseVersion" has been specified. If it has,
|
||||
* use its value to determine the requested version. If not use the value of the "multi-release" property.
|
||||
*/
|
||||
private void initializeReleaseVersion(Map<String, ?> env) throws IOException {
|
||||
Object o = env.containsKey(PROPERTY_RELEASE_VERSION) ?
|
||||
env.get(PROPERTY_RELEASE_VERSION) :
|
||||
env.get(PROPERTY_MULTI_RELEASE);
|
||||
|
||||
if (o != null && isMultiReleaseJar()) {
|
||||
int version;
|
||||
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 {
|
||||
throw new IllegalArgumentException("Invalid runtime version");
|
||||
}
|
||||
} else if (o instanceof Integer) {
|
||||
version = Version.parse(((Integer)o).toString()).feature();
|
||||
} else if (o instanceof Version) {
|
||||
version = ((Version)o).feature();
|
||||
} else {
|
||||
throw new IllegalArgumentException("env parameter must be String, " +
|
||||
"Integer, or Version");
|
||||
}
|
||||
createVersionedLinks(version < 0 ? 0 : version);
|
||||
setReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Manifest main attribute "Multi-Release" is set to true; false otherwise.
|
||||
*/
|
||||
private boolean isMultiReleaseJar() throws IOException {
|
||||
try (InputStream is = newInputStream(getBytes("/META-INF/MANIFEST.MF"))) {
|
||||
String multiRelease = new Manifest(is).getMainAttributes()
|
||||
.getValue(Attributes.Name.MULTI_RELEASE);
|
||||
return "true".equalsIgnoreCase(multiRelease);
|
||||
} catch (NoSuchFileException x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a map of aliases for versioned entries, for example:
|
||||
* version/PackagePrivate.class -> META-INF/versions/9/version/PackagePrivate.class
|
||||
* version/PackagePrivate.java -> META-INF/versions/9/version/PackagePrivate.java
|
||||
* version/Version.class -> META-INF/versions/10/version/Version.class
|
||||
* version/Version.java -> META-INF/versions/10/version/Version.java
|
||||
*
|
||||
* Then wrap the map in a function that getEntry can use to override root
|
||||
* entry lookup for entries that have corresponding versioned entries.
|
||||
*/
|
||||
private void createVersionedLinks(int version) {
|
||||
IndexNode verdir = getInode(getBytes("/META-INF/versions"));
|
||||
// nothing to do, if no /META-INF/versions
|
||||
if (verdir == null) {
|
||||
return;
|
||||
}
|
||||
// otherwise, create a map and for each META-INF/versions/{n} directory
|
||||
// put all the leaf inodes, i.e. entries, into the alias map
|
||||
// possibly shadowing lower versioned entries
|
||||
HashMap<IndexNode, byte[]> aliasMap = new HashMap<>();
|
||||
getVersionMap(version, verdir).values().forEach(versionNode ->
|
||||
walk(versionNode.child, entryNode ->
|
||||
aliasMap.put(
|
||||
getOrCreateInode(getRootName(entryNode, versionNode), entryNode.isdir),
|
||||
entryNode.name))
|
||||
);
|
||||
entryLookup = path -> {
|
||||
byte[] entry = aliasMap.get(IndexNode.keyOf(path));
|
||||
return entry == null ? path : entry;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sorted version map of version -> inode, for inodes <= max version.
|
||||
* 9 -> META-INF/versions/9
|
||||
* 10 -> META-INF/versions/10
|
||||
*/
|
||||
private TreeMap<Integer, IndexNode> getVersionMap(int version, IndexNode metaInfVersions) {
|
||||
TreeMap<Integer,IndexNode> map = new TreeMap<>();
|
||||
IndexNode child = metaInfVersions.child;
|
||||
while (child != null) {
|
||||
Integer key = getVersion(child, metaInfVersions);
|
||||
if (key != null && key <= version) {
|
||||
map.put(key, child);
|
||||
}
|
||||
child = child.sibling;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the integer version number -- META-INF/versions/9 returns 9.
|
||||
*/
|
||||
private Integer getVersion(IndexNode inode, IndexNode metaInfVersions) {
|
||||
try {
|
||||
byte[] fullName = inode.name;
|
||||
return Integer.parseInt(getString(Arrays
|
||||
.copyOfRange(fullName, metaInfVersions.name.length + 1, fullName.length)));
|
||||
} catch (NumberFormatException x) {
|
||||
// ignore this even though it might indicate issues with the JAR structure
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the IndexNode tree processing all leaf nodes.
|
||||
*/
|
||||
private void walk(IndexNode inode, Consumer<IndexNode> consumer) {
|
||||
if (inode == null) return;
|
||||
if (inode.isDir()) {
|
||||
walk(inode.child, consumer);
|
||||
} else {
|
||||
consumer.accept(inode);
|
||||
}
|
||||
walk(inode.sibling, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the root name from a versioned entry name.
|
||||
* E.g. given inode 'META-INF/versions/9/foo/bar.class'
|
||||
* and prefix 'META-INF/versions/9/' returns 'foo/bar.class'.
|
||||
*/
|
||||
private byte[] getRootName(IndexNode inode, IndexNode prefix) {
|
||||
byte[] fullName = inode.name;
|
||||
return Arrays.copyOfRange(fullName, prefix.name.length, fullName.length);
|
||||
}
|
||||
|
||||
// Reads zip file central directory. Returns the file position of first
|
||||
// CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL
|
||||
// then the error was a zip format error and zip->msg has the error text.
|
||||
@ -1644,15 +1795,15 @@ class ZipFileSystem extends FileSystem {
|
||||
hasUpdate = false; // clear
|
||||
}
|
||||
|
||||
IndexNode getInode(byte[] path) {
|
||||
return inodes.get(IndexNode.keyOf(Objects.requireNonNull(path, "path")));
|
||||
private IndexNode getInode(byte[] path) {
|
||||
return inodes.get(IndexNode.keyOf(Objects.requireNonNull(entryLookup.apply(path), "path")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IndexNode from the root tree. If it doesn't exist,
|
||||
* it gets created along with all parent directory IndexNodes.
|
||||
*/
|
||||
IndexNode getOrCreateInode(byte[] path, boolean isdir) {
|
||||
private IndexNode getOrCreateInode(byte[] path, boolean isdir) {
|
||||
IndexNode node = getInode(path);
|
||||
// if node exists, return it
|
||||
if (node != null) {
|
||||
@ -2248,7 +2399,7 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
private static final ThreadLocal<IndexNode> cachedKey = new ThreadLocal<>();
|
||||
|
||||
final static IndexNode keyOf(byte[] name) { // get a lookup key;
|
||||
static final IndexNode keyOf(byte[] name) { // get a lookup key;
|
||||
IndexNode key = cachedKey.get();
|
||||
if (key == null) {
|
||||
key = new IndexNode(name, -1);
|
||||
|
@ -52,12 +52,6 @@ import java.util.zip.ZipException;
|
||||
* @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
|
||||
*/
|
||||
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() {}
|
||||
@ -127,21 +121,14 @@ public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
}
|
||||
|
||||
private ZipFileSystem getZipFileSystem(Path path, Map<String, ?> env) throws IOException {
|
||||
ZipFileSystem zipfs;
|
||||
try {
|
||||
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 new ZipFileSystem(this, path, env);
|
||||
} catch (ZipException ze) {
|
||||
String pname = path.toString();
|
||||
if (pname.endsWith(".zip") || pname.endsWith(".jar"))
|
||||
throw ze;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return zipfs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 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
|
||||
@ -54,9 +54,9 @@ public class ModulesInCustomFileSystem {
|
||||
private static final Path HERE = Paths.get("");
|
||||
|
||||
/**
|
||||
* Test exploded modules in a JAR file system.
|
||||
* Test exploded modules in a Zip file system.
|
||||
*/
|
||||
public void testExplodedModulesInJarFileSystem() throws Exception {
|
||||
public void testExplodedModulesInZipFileSystem() throws Exception {
|
||||
Path m1 = findModuleDirectory("m1");
|
||||
Path m2 = findModuleDirectory("m2");
|
||||
Path mlib = m1.getParent();
|
||||
@ -65,13 +65,13 @@ public class ModulesInCustomFileSystem {
|
||||
// create JAR file containing m1/** and m2/**
|
||||
Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
|
||||
JarUtils.createJarFile(jar, mlib);
|
||||
testJarFileSystem(jar);
|
||||
testZipFileSystem(jar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test modular JARs in a JAR file system
|
||||
* Test modular JARs in a Zip file system.
|
||||
*/
|
||||
public void testModularJARsInJarFileSystem() throws Exception {
|
||||
public void testModularJARsInZipFileSystem() throws Exception {
|
||||
Path m1 = findModuleDirectory("m1");
|
||||
Path m2 = findModuleDirectory("m2");
|
||||
Path contents = Files.createTempDirectory(HERE, "contents");
|
||||
@ -81,15 +81,14 @@ public class ModulesInCustomFileSystem {
|
||||
// create JAR file containing m1.jar and m2.jar
|
||||
Path jar = Files.createTempDirectory(HERE, "mlib").resolve("modules.jar");
|
||||
JarUtils.createJarFile(jar, contents);
|
||||
testJarFileSystem(jar);
|
||||
testZipFileSystem(jar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a JAR file as a file system
|
||||
*/
|
||||
private void testJarFileSystem(Path jar) throws Exception {
|
||||
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||
try (FileSystem fs = FileSystems.newFileSystem(jar, scl)) {
|
||||
private void testZipFileSystem(Path zip) throws Exception {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zip)) {
|
||||
// ModuleFinder to find modules in top-level directory
|
||||
Path top = fs.getPath("/");
|
||||
ModuleFinder finder = ModuleFinder.of(top);
|
||||
|
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8164389 8222440
|
||||
* @summary walk entries in a jdk.nio.zipfs.JarFileSystem
|
||||
* @summary walk entries in a multi-release jar file via jdk.zipfs
|
||||
* @library /lib/testlibrary/java/util/jar
|
||||
* @modules jdk.jartool
|
||||
* jdk.zipfs
|
||||
|
@ -50,6 +50,8 @@ import org.testng.annotations.*;
|
||||
|
||||
public class MultiReleaseJarTest {
|
||||
final private int MAJOR_VERSION = Runtime.version().feature();
|
||||
private static final String PROPERTY_RELEASE_VERSION = "releaseVersion";
|
||||
private static final String PROPERTY_MULTI_RELEASE = "multi-release";
|
||||
|
||||
final private String userdir = System.getProperty("user.dir",".");
|
||||
final private CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
|
||||
@ -88,56 +90,56 @@ public class MultiReleaseJarTest {
|
||||
@DataProvider(name="strings")
|
||||
public Object[][] createStrings() {
|
||||
return new Object[][]{
|
||||
{"runtime", MAJOR_VERSION},
|
||||
{null, 8},
|
||||
{"8", 8},
|
||||
{"9", 9},
|
||||
{Integer.toString(MAJOR_VERSION), MAJOR_VERSION},
|
||||
{Integer.toString(MAJOR_VERSION+1), MAJOR_VERSION},
|
||||
{"50", MAJOR_VERSION}
|
||||
{"runtime", MAJOR_VERSION, "8"},
|
||||
{null, 8, Integer.toString(MAJOR_VERSION)},
|
||||
{"8", 8, "9"},
|
||||
{"9", 9, null},
|
||||
{Integer.toString(MAJOR_VERSION), MAJOR_VERSION, "8"},
|
||||
{Integer.toString(MAJOR_VERSION+1), MAJOR_VERSION, "8"},
|
||||
{"50", MAJOR_VERSION, "9"}
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider(name="integers")
|
||||
public Object[][] createIntegers() {
|
||||
return new Object[][] {
|
||||
{null, 8},
|
||||
{Integer.valueOf(8), 8},
|
||||
{Integer.valueOf(9), 9},
|
||||
{Integer.valueOf(MAJOR_VERSION), MAJOR_VERSION},
|
||||
{Integer.valueOf(MAJOR_VERSION + 1), MAJOR_VERSION},
|
||||
{Integer.valueOf(100), MAJOR_VERSION}
|
||||
{null, 8, Integer.valueOf(9)},
|
||||
{Integer.valueOf(8), 8, Integer.valueOf(9)},
|
||||
{Integer.valueOf(9), 9, Integer.valueOf(MAJOR_VERSION)},
|
||||
{Integer.valueOf(MAJOR_VERSION), MAJOR_VERSION, Integer.valueOf(8)},
|
||||
{Integer.valueOf(MAJOR_VERSION + 1), MAJOR_VERSION, null},
|
||||
{Integer.valueOf(100), MAJOR_VERSION, Integer.valueOf(8)}
|
||||
};
|
||||
}
|
||||
|
||||
@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},
|
||||
{Version.parse(Integer.toString(MAJOR_VERSION) + 1), MAJOR_VERSION},
|
||||
{Version.parse("100"), MAJOR_VERSION}
|
||||
{null, 8, Version.parse("14")},
|
||||
{Version.parse("8"), 8, Version.parse("7")},
|
||||
{Version.parse("9"), 9, null},
|
||||
{Version.parse(Integer.toString(MAJOR_VERSION)), MAJOR_VERSION, Version.parse("8")},
|
||||
{Version.parse(Integer.toString(MAJOR_VERSION) + 1), MAJOR_VERSION, Version.parse("9")},
|
||||
{Version.parse("100"), MAJOR_VERSION, Version.parse("14")}
|
||||
};
|
||||
}
|
||||
|
||||
@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))}
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, "")},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, "invalid")},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, "0")},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, "-1")},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, "11.0.1")},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, new ArrayList<Long>())},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, Integer.valueOf(0))},
|
||||
{Map.of(PROPERTY_RELEASE_VERSION, 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 ...)
|
||||
// Not the best test but all I can do since ZipFileSystem
|
||||
// is not public, so I can't use (fs instanceof ...)
|
||||
@Test
|
||||
public void testNewFileSystem() throws Exception {
|
||||
Map<String,String> env = new HashMap<>();
|
||||
@ -145,7 +147,7 @@ public class MultiReleaseJarTest {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
|
||||
Assert.assertTrue(readAndCompare(fs, 8));
|
||||
}
|
||||
env.put("releaseVersion", "runtime");
|
||||
env.put(PROPERTY_RELEASE_VERSION, "runtime");
|
||||
// a configuration and jar file is multi-release
|
||||
try (FileSystem fs = FileSystems.newFileSystem(mruri, env)) {
|
||||
Assert.assertTrue(readAndCompare(fs, MAJOR_VERSION));
|
||||
@ -163,28 +165,38 @@ public class MultiReleaseJarTest {
|
||||
}
|
||||
|
||||
@Test(dataProvider="strings")
|
||||
public void testStrings(String value, int expected) throws Throwable {
|
||||
stringEnv.put("releaseVersion", value);
|
||||
public void testStrings(String value, int expected, String ignorable) throws Throwable {
|
||||
stringEnv.clear();
|
||||
stringEnv.put(PROPERTY_RELEASE_VERSION, value);
|
||||
// we check, that values for "multi-release" are ignored
|
||||
stringEnv.put(PROPERTY_MULTI_RELEASE, ignorable);
|
||||
runTest(stringEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="integers")
|
||||
public void testIntegers(Integer value, int expected) throws Throwable {
|
||||
integerEnv.put("releaseVersion", value);
|
||||
public void testIntegers(Integer value, int expected, Integer ignorable) throws Throwable {
|
||||
integerEnv.clear();
|
||||
integerEnv.put(PROPERTY_RELEASE_VERSION, value);
|
||||
// we check, that values for "multi-release" are ignored
|
||||
integerEnv.put(PROPERTY_MULTI_RELEASE, value);
|
||||
runTest(integerEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="versions")
|
||||
public void testVersions(Version value, int expected) throws Throwable {
|
||||
versionEnv.put("releaseVersion", value);
|
||||
public void testVersions(Version value, int expected, Version ignorable) throws Throwable {
|
||||
versionEnv.clear();
|
||||
versionEnv.put(PROPERTY_RELEASE_VERSION, value);
|
||||
// we check, that values for "multi-release" are ignored
|
||||
versionEnv.put(PROPERTY_MULTI_RELEASE, ignorable);
|
||||
runTest(versionEnv, expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortJar() throws Throwable {
|
||||
integerEnv.put("releaseVersion", Integer.valueOf(MAJOR_VERSION));
|
||||
integerEnv.clear();
|
||||
integerEnv.put(PROPERTY_RELEASE_VERSION, Integer.valueOf(MAJOR_VERSION));
|
||||
runTest(smruri, integerEnv, MAJOR_VERSION);
|
||||
integerEnv.put("releaseVersion", Integer.valueOf(9));
|
||||
integerEnv.put(PROPERTY_RELEASE_VERSION, Integer.valueOf(9));
|
||||
runTest(smruri, integerEnv, 8);
|
||||
}
|
||||
|
||||
@ -205,23 +217,23 @@ public class MultiReleaseJarTest {
|
||||
// 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 {
|
||||
public void testMRStrings(String value, int expected, String ignorable) throws Throwable {
|
||||
stringEnv.clear();
|
||||
stringEnv.put("multi-release", value);
|
||||
stringEnv.put(PROPERTY_MULTI_RELEASE, value);
|
||||
runTest(stringEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="integers")
|
||||
public void testMRIntegers(Integer value, int expected) throws Throwable {
|
||||
public void testMRIntegers(Integer value, int expected, Integer ignorable) throws Throwable {
|
||||
integerEnv.clear();
|
||||
integerEnv.put("multi-release", value);
|
||||
integerEnv.put(PROPERTY_MULTI_RELEASE, value);
|
||||
runTest(integerEnv, expected);
|
||||
}
|
||||
|
||||
@Test(dataProvider="versions")
|
||||
public void testMRVersions(Version value, int expected) throws Throwable {
|
||||
public void testMRVersions(Version value, int expected, Version ignorable) throws Throwable {
|
||||
versionEnv.clear();
|
||||
versionEnv.put("multi-release", value);
|
||||
versionEnv.put(PROPERTY_MULTI_RELEASE, value);
|
||||
runTest(versionEnv, expected);
|
||||
}
|
||||
|
||||
@ -264,7 +276,7 @@ public class MultiReleaseJarTest {
|
||||
JarBuilder jb = new JarBuilder(jfname);
|
||||
jb.addAttribute("Multi-Release", "true");
|
||||
jb.build();
|
||||
Map<String,String> env = Map.of("releaseVersion", "runtime");
|
||||
Map<String,String> env = Map.of(PROPERTY_RELEASE_VERSION, "runtime");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
@ -279,7 +291,7 @@ public class MultiReleaseJarTest {
|
||||
creator.buildCustomMultiReleaseJar(fileName, value, Map.of(),
|
||||
/*addEntries*/true);
|
||||
|
||||
Map<String,String> env = Map.of("releaseVersion", "runtime");
|
||||
Map<String,String> env = Map.of(PROPERTY_RELEASE_VERSION, "runtime");
|
||||
Path filePath = Paths.get(userdir, fileName);
|
||||
String ssp = filePath.toUri().toString();
|
||||
URI customJar = new URI("jar", ssp , null);
|
||||
|
Loading…
Reference in New Issue
Block a user