
io.qt.internal.ResourceUtility Maven / Gradle / Ivy
/****************************************************************************
**
** Copyright (C) 2009-2024 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** $END_LICENSE$
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package io.qt.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import io.qt.NativeAccess;
import io.qt.core.QDir;
import io.qt.core.QLocale;
/**
* @hidden
*/
final class ResourceUtility {
static {
QtJambi_LibraryUtilities.initialize();
}
private ResourceUtility() {
}
private interface JarResourceFactoryInterface{
JarResource create(File fileToJarFile) throws IOException;
JarResource create(URL urlToJarFile) throws IOException;
}
private static class JarResourceFactory implements JarResourceFactoryInterface{
@Override
public JarResource create(File fileToJarFile) throws IOException {
return new JarResource(fileToJarFile);
}
@Override
public JarResource create(URL urlToJarFile) throws IOException {
return new JarResource(urlToJarFile);
}
}
private static class RecognizableJarResourceFactory implements JarResourceFactoryInterface{
@Override
public JarResource create(File fileToJarFile) throws IOException {
return new RecognizableJarResource(fileToJarFile);
}
@Override
public JarResource create(URL urlToJarFile) throws IOException {
return new RecognizableJarResource(urlToJarFile);
}
}
private final static JarResourceFactoryInterface factory;
static {
if(Boolean.getBoolean("io.qt.acknowledge-resources")) {
factory = new RecognizableJarResourceFactory();
}else {
factory = new JarResourceFactory();
}
}
private static class UrlOrFile {
UrlOrFile(URL url, File file) {
super();
this.url = url;
this.file = file;
}
final URL url;
final File file;
}
private static final Function> newSetFactory = s -> new HashSet<>();
private final static JarCache cache = new JarCache();
static void addSearchPath(URL url) {
if (url != null) {
cache.addPath(url);
}
}
static void addSearchPath(String path) {
URL url = resolveUrlFromPath(path);
if (url != null) {
cache.addPath(url);
}
}
static void removeSearchPath(String path) {
URL url = resolveUrlFromPath(path);
if (url != null) {
cache.removePath(url);
}
}
@NativeAccess
private static void initialize() {
List cpUrls = new ArrayList<>();
try {
for(URI uri : RetroHelper.moduleLocations()) {
try{
URL url = uri.toURL();
if(!"jrt".equals(url.getProtocol()) && !cpUrls.contains(url)) {
cache.addPath(url);
cpUrls.add(url);
}
} catch (Exception e) {
java.util.logging.Logger.getLogger("io.qt.internal.fileengine").log(java.util.logging.Level.SEVERE, "", e);
}
}
for(ClassLoader loader : RetroHelper.classLoaders()) {
if(loader instanceof URLClassLoader) {
for(URL url : ((URLClassLoader) loader).getURLs()) {
if(!cpUrls.contains(url)) {
cache.addPath(url);
cpUrls.add(url);
}
}
}else {
Enumeration urls = loader.getResources("META-INF/MANIFEST.MF");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
try {
String end;
String urlPath;
if("jar".equals(url.getProtocol())) {
urlPath = url.getPath();
end = "!/META-INF/MANIFEST.MF";
}else {
urlPath = url.toString();
end = "/META-INF/MANIFEST.MF";
if(urlPath.endsWith(end))
end = "META-INF/MANIFEST.MF";
}
if(urlPath.endsWith(end)) {
urlPath = urlPath.substring(0, urlPath.length() - end.length());
URL fileUrl = CoreUtility.createURL(urlPath);
if(!"jar".equals(url.getProtocol()) && fileUrl.getPath().isEmpty()) {
fileUrl = CoreUtility.createURL(urlPath+"/");
}
if(!cpUrls.contains(fileUrl)) {
cache.addPath(fileUrl);
cpUrls.add(fileUrl);
}
}
} catch (Throwable e) {
java.util.logging.Logger.getLogger("io.qt.internal.fileengine")
.log(java.util.logging.Level.SEVERE, "", e);
}
}
}
}
} catch (Exception e) {
java.util.logging.Logger.getLogger("io.qt.internal.fileengine").log(java.util.logging.Level.SEVERE, "",
e);
}
String javaClassPath = System.getProperty("java.class.path");
if (javaClassPath == null)
javaClassPath = ""; // gets ignored below
String javaModulePath = System.getProperty("jdk.module.path");
if (javaModulePath != null)
javaClassPath = javaModulePath + File.pathSeparator + javaClassPath; // gets ignored below
String paths[] = javaClassPath.split("\\" + File.pathSeparator);
// Only add the .jar files that are not already added...
int counter = 0;
for (String path : paths) {
path = path.trim();
if (!path.isEmpty()) {
counter++; // count all paths, invalid and valid
URL url = resolveUrlFromPath(path);
boolean match = false;
if(url!=null){
cache.addPath(url);
if(url.toString().endsWith("/"))
continue;
}else{
continue;
}
JarResource resource2 = null;
JarResource resource1 = null;
try {
resource2 = resolveUrlToJarResource(url);
if (resource2 != null) {
for (URL otherURL : cpUrls) {
if(otherURL.toString().endsWith("/"))
continue;
resource1 = resolveUrlToJarResource(otherURL);
if (resource1 != null) {
File file1 = new File(resource1.getName());
File file2 = new File(resource2.getName());
if (file1.getCanonicalPath().equals(file2.getCanonicalPath())) {
match = true;
break;
}
}
}
}
} catch (Exception e) { // This should probably just be IOException
java.util.logging.Logger.getLogger("io.qt.internal.fileengine")
.log(java.util.logging.Level.SEVERE, "", e); // this has been so useful in finding many
// bugs/issues
} finally {
if (resource2 != null) {
resource2.put();
resource2 = null;
}
if (resource1 != null) {
resource1.put();
resource1 = null;
}
}
if (!match)
cache.addPath(url);
}
}
if (counter == 0) {
try {
cache.addPath(new File(System.getProperty("user.dir")).toURI().toURL());
} catch (MalformedURLException e) {
java.util.logging.Logger.getLogger("io.qt.internal.fileengine")
.log(java.util.logging.Level.SEVERE, "", e);
}
}
}
@NativeAccess
private static URL resolveUrlFromPath(String path) {
URL result = null;
if (path != null) {
File file = new File(path);
if(file.exists()) {
try {
result = file.toURI().toURL();
} catch (Exception e) {
}
}
if(result==null) {
try {
result = CoreUtility.createURL(path);
} catch (Exception e) {
}
}
if(result==null) {
final int pathLength = path.length();
boolean skipTryAsis = false; // attempt to not use exceptions for common situations
if (pathLength > 0) {
char firstChar = path.charAt(0);
// Both a "/" and "\\" are illegal characters in the scheme/protocol.
if (firstChar == File.separatorChar) {
skipTryAsis = true;
} else if (pathLength == 1) {
if (firstChar == '.') {
String tmpPath = System.getProperty("user.dir");
if (tmpPath != null) {
path = tmpPath;
skipTryAsis = true;
}
}
// ELSE it is a relative path and will be picked up below
} else if (pathLength > 1) {
char secondChar = path.charAt(1);
if (firstChar == '.' && secondChar == File.separatorChar) {
// ./foo/bar case
String tmpPath = System.getProperty("user.dir");
if (tmpPath != null) {
path = tmpPath + File.separatorChar + path.substring(2);
skipTryAsis = true;
}
} else if (pathLength > 2) {
// Windows "C:\\..." for which "\\" is incorrect for URLs
char thirdChar = path.charAt(2);
if ((firstChar >= 'A' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'z')) {
// We don't check for '/' since that might be a real URL "a://host:port/path?qs"
// and would be invalid for windows using java.io.File API anyway.
if (secondChar == ':' && thirdChar == '\\')
skipTryAsis = true;
if (secondChar == ':' && thirdChar == '/') // "C:/dir1/dir2/file.dat" is seen when processing
// paths from QFileInfo
skipTryAsis = true;
} else if (pathLength > 3) {
// Eclipse "/C:/..."
char fourthChar = path.charAt(3);
if (firstChar == '/' && (secondChar >= 'A' && secondChar <= 'Z')
|| (secondChar >= 'a' && secondChar <= 'z')) {
if (thirdChar == ':' && fourthChar == '/')
skipTryAsis = true; // we prefix it with file:// below
}
}
}
}
if (skipTryAsis == false) {
boolean prefix = !(path.startsWith("file:")
|| path.startsWith("jar:")
|| path.startsWith("http:")
|| path.startsWith("https:"));
int colon = path.indexOf(':');
if(colon>0) {
String protocol = path.substring(0, colon);
try {
CoreUtility.createURL(protocol+"://");
prefix = false;
} catch (MalformedURLException e) {
}
}
if (prefix) {
String tmpPath = System.getProperty("user.dir");
if (tmpPath != null) {
String _path = tmpPath + File.separatorChar + path;
if(new File(_path).exists()) {
path = _path;
skipTryAsis = true;
}
}
}
}
}
if (result == null) {
try {
String xPath = path.replace('\\', '/');
String xPrefix;
if (path.length() > 0 && xPath.charAt(0) != '/')
xPrefix = "file:///";
else
xPrefix = "file://";
String newTmpPath = xPrefix;
if (File.separatorChar == '\\')
newTmpPath += path.replace('\\', '/'); // windows
else
newTmpPath += path;
result = CoreUtility.createURL(newTmpPath);
} catch (Exception e) {
}
}
}
try {
UrlOrFile urlOrFile = checkURL(result);
if (urlOrFile.file != null) { // Due to workaround
if (!urlOrFile.file.exists())
result = null;
} else if(!urlOrFile.url.toString().endsWith("/") && !urlOrFile.url.getPath().isEmpty()){
URLConnection urlConn = urlOrFile.url.openConnection();
try(InputStream inStream = urlConn.getInputStream()){}
}
} catch(java.io.FileNotFoundException e) {
result = null;
} catch (Throwable e) {
if(!result.getProtocol().equals("jrt") && !result.getProtocol().equals("file"))
java.util.logging.Logger.getLogger("io.qt.internal.fileengine").log(java.util.logging.Level.SEVERE, ""+result, e);
result = null;
}
}
return result;
}
@NativeAccess
private static Collection pathToJarFiles(String entry) {
return cache.pathToJarFiles(entry);
}
@NativeAccess
private static boolean isDirectory(JarResource myJarFile, String fileName) {
boolean isDirectory = false;
JarEntry fileInJar = myJarFile.getJarEntry(fileName);
// If the entry exists in the given file, look it up and
// check if its a dir or not
if (fileInJar != null) {
isDirectory = fileInJar.isDirectory();
if (!isDirectory) {
boolean tmpIsDirectory = checkIsDirectory(myJarFile, fileInJar);
isDirectory = tmpIsDirectory;
} else {
}
}
if (!isDirectory) {
// Otherwise, look if the directory exists in the
// cache...
Collection pathToJarFiles = pathToJarFiles(fileName);
String jarFileName = myJarFile.getName();
if (pathToJarFiles != null) {
for (String thisPathToJar : pathToJarFiles) {
if (thisPathToJar.equals(jarFileName)) {
isDirectory = true;
break;
}
}
}
// Nasty fallback... Iterate through the .jar file and try to check if
// fileName is the prefix (hence directory) of any of the entries...
if (!isDirectory) {
String fileNameWithSlash = fileName + "/";
Enumeration entries = myJarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entryName.startsWith(fileNameWithSlash)) {
isDirectory = true;
break;
}
}
}
}
return isDirectory;
}
/**
* The JarEntry.isDirectory() method in Java returns false
* even for directories, so we need this extra check
* which tries to read a byte from the entry in order
* to trigger an exception when the entry is a directory.
*/
static boolean checkIsDirectory(JarResource myJarFile, JarEntry fileInJar) {
InputStream inStream = null;
try {
// CHECKME is this hack/trick/kludge maybe somewhat problematic
// for connection handler based JarFile handles ?
inStream = myJarFile.getInputStream(fileInJar);
if(inStream == null)
return true; // avoid NPE
inStream.read();
} catch(IOException e) {
return true;
} finally {
if(inStream != null) {
try {
inStream.close();
} catch(IOException eat) {
}
inStream = null;
}
}
return false;
}
@NativeAccess
private static JarResource resolveUrlToJarResource(URL url) throws IOException, ZipException {
JarResource myJarFile = null;
UrlOrFile urlOrFile = checkURL(url);
try {
if(urlOrFile.file != null) { // Due to workaround
if(urlOrFile.file.isFile()) // skip dirs
myJarFile = factory.create(urlOrFile.file);
} else if(!"jrt".equals(urlOrFile.url.getProtocol())){
myJarFile = factory.create(urlOrFile.url);
}
} catch(ZipException e) {
// This often fails with "java.util.zip.ZipException: error in opening zip file" but never discloses the filename
throw new ZipException(e.getMessage() + ": " + url);
}
return myJarFile;
}
private static UrlOrFile checkURL(URL url) {
File file = null;
if("jar".equals(url.getProtocol())) {
String path = url.getPath();
if(path.endsWith("!/")) {
try {
url = CoreUtility.createURL(path.substring(0, path.length() - 2));
return checkURL(url);
} catch(MalformedURLException eat) {
url = null;
}
}
} else if("file".equals(url.getProtocol())) {
try {
file = new File(url.toURI());
} catch (URISyntaxException e) {
}
}
return new UrlOrFile(url, file);
}
private static class JarResource{
private URLConnection urlConnection; // do we need to keep this around ?
private File fileToJarFile; // we store this object type to differentiate between URLs and direct File IO.
private URL urlToJarFile; // we save this to allow for close/reopen based on just this handle
private JarFile jarFile;
private int refCount;
JarResource(File fileToJarFile) throws IOException {
this.fileToJarFile = fileToJarFile;
openInternal();
}
JarResource(URL urlToJarFile) throws IOException {
this.urlToJarFile = urlToJarFile;
openInternal();
}
private void openInternal() throws IOException {
if(fileToJarFile != null) { // Direct File I/O Jar file
jarFile = new JarFile(fileToJarFile);
} else {
urlConnection = urlToJarFile.openConnection();
if(urlConnection instanceof JarURLConnection) {
JarURLConnection jarUrlConnection = (JarURLConnection) urlConnection;
jarFile = jarUrlConnection.getJarFile();
}else {
IOException thr = new IOException("not a JarURLConnection: " + urlConnection.getClass().getName()+" for URL: "+urlToJarFile);
urlConnection = null; // we only keep handle when we have active Jar open
throw thr;
}
}
refCount = 1;
}
// This method may never throw an exception
@NativeAccess
final void get() {
synchronized(this) {
refCount++;
}
}
// This method must cause a double increment on the reopen() case
// Returns the previous refCount, so 0 means we just reopened, non-zero means we did get()
@NativeAccess
final int getOrReopen() throws IOException {
int oldRefCount;
synchronized (this) {
oldRefCount = refCount;
if(refCount <= 0)
reopen();
get();
}
return oldRefCount;
}
// This method may never throw an exception
@NativeAccess
final void put() {
JarFile closeJarFile = null;
synchronized(this) {
refCount--;
if(refCount == 0) {
closeJarFile = jarFile;
jarFile = null;
}
}
if(closeJarFile != null) {
try {
closeJarFile.close();
} catch(IOException eat) {
}
if(urlConnection != null) {
urlConnection = null;
}
}
}
final void reopen() throws IOException {
if(jarFile != null)
throw new IOException("jarFile already open");
openInternal();
}
@NativeAccess
final String getName() {
return jarFile.getName();
}
Enumeration entries() {
return jarFile.entries();
}
@NativeAccess
JarEntry getJarEntry(String name) {
JarEntry entry = jarFile.getJarEntry(name);
if(entry==null) {
JarEntry aliasEntry = jarFile.getJarEntry(name+".alias");
if(aliasEntry!=null) {
try(InputStream stream = getInputStream(aliasEntry)){
Properties aliasProperties = new Properties();
aliasProperties.load(stream);
QLocale locale = new QLocale();
String localeName = locale.name();
String aliasName = aliasProperties.getProperty(localeName);
if(aliasName==null && !locale.bcp47Name().equals(localeName)) {
aliasName = aliasProperties.getProperty(locale.bcp47Name());
}
if(aliasName==null) {
String[] split = localeName.split("_");
if(split.length>1)
aliasName = aliasProperties.getProperty(split[0]);
}
if(aliasName==null) {
aliasName = aliasProperties.getProperty("default");
}
if(aliasName==null) {
aliasName = aliasProperties.getProperty("");
}
if(aliasName!=null) {
int idx = name.lastIndexOf('/');
if(idx>0) {
String path = name.substring(0, idx+1);
entry = jarFile.getJarEntry(path + aliasName);
}else{
entry = jarFile.getJarEntry(aliasName);
}
}
} catch (Throwable ign) {
}
}
}
return entry;
}
@NativeAccess
InputStream getInputStream(ZipEntry ze) throws IOException {
return jarFile.getInputStream(ze);
}
@NativeAccess
private void entryList(List result, int _filters, Collection filterNames, String mentryName){
if (!mentryName.endsWith("/") && mentryName.length() > 0)
mentryName = mentryName + "/";
Enumeration entries = entries();
HashSet used = new HashSet();
QDir.Filters filters = new QDir.Filters(_filters);
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
// Must be inside this directory
if (entryName.length() <= mentryName.length() || !mentryName.equals(entryName.substring(0, mentryName.length())) || mentryName.equals(entryName))
continue;
// Only one level
boolean isDir;
int pos = entryName.indexOf("/", mentryName.length());
if (pos > 0) {
entryName = entryName.substring(0, pos);
isDir = true;
} else {
isDir = entry.isDirectory();
if (!isDir)
isDir = ResourceUtility.checkIsDirectory(this, entry);
}
if (!filters.testFlag(QDir.Filter.Readable))
continue ;
if (!filters.testFlag(QDir.Filter.Dirs) && isDir)
continue ;
if (!filters.testFlag(QDir.Filter.Files) && !isDir)
continue ;
if (filterNames.size() > 0) {
if ((!isDir || !filters.testFlag(QDir.Filter.AllDirs))
&& (!QDir.match(filterNames, entryName.substring(mentryName.length())))) {
continue;
}
}
if (entryName.endsWith("/") && entryName.length() > 1)
entryName = entryName.substring(0, entryName.length() - 1);
entryName = entryName.substring(mentryName.length());
if (!used.contains(entryName)) {
used.add(entryName);
result.add(entryName);
}
}
}
@NativeAccess
private long fileTime(ZipEntry ze, boolean creationTime, boolean lastAccessTime, boolean lastModified) throws IOException {
FileTime fileTime = null;
if(ze!=null) {
if(creationTime)
fileTime = ze.getCreationTime();
else if(lastAccessTime)
fileTime = ze.getLastAccessTime();
else if(lastModified)
fileTime = ze.getLastModifiedTime();
else
fileTime = ze.getCreationTime();
}else if(fileToJarFile!=null){
fileTime = Files.getLastModifiedTime(fileToJarFile.toPath());
}
if(fileTime!=null) {
return fileTime.toMillis();
}else {
long tm = -1;
if(ze!=null){
tm = ze.getTime();
}else if(fileToJarFile!=null){
tm = fileToJarFile.lastModified();
}
return tm;
}
}
}
private static final class RecognizableJarResource extends JarResource{
RecognizableJarResource(URL urlToJarFile) throws IOException {
super(urlToJarFile);
}
RecognizableJarResource(File fileToJarFile) throws IOException {
super(fileToJarFile);
}
@Override
JarEntry getJarEntry(String name) {
JarEntry entry = super.getJarEntry(name);
if(entry!=null) {
try {
ResourceUtility.class.getClassLoader().getResource(entry.getName());
} catch (Exception e) {
}
}
return entry;
}
@Override
InputStream getInputStream(ZipEntry entry) throws IOException {
if(entry!=null) {
try {
ResourceUtility.class.getClassLoader().getResource(entry.getName());
} catch (Exception e) {
}
}
return super.getInputStream(entry);
}
@Override
Enumeration entries() {
Enumeration entries = super.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if(entry!=null) {
try {
ResourceUtility.class.getClassLoader().getResource(entry.getName());
} catch (Exception e) {
}
}
}
return super.entries();
}
}
@NativeAccess
private static Collection classPathDirs() {
return cache.classPathDirs();
}
@NativeAccess
private static void clear() {
synchronized(cache.cache) {
cache.cache.clear();
}
synchronized(cache.classPathDirs) {
cache.classPathDirs.clear();
}
}
private final static class JarCache {
Collection pathToJarFiles(String entry) {
synchronized(cache) {
Set result = cache.get(entry);
return result==null? Collections.emptyList() : new HashSet<>(result);
}
}
Collection classPathDirs() {
synchronized(classPathDirs) {
return new HashSet<>(classPathDirs);
}
}
private final Map> cache = new HashMap<>();
private final Set classPathDirs = new HashSet<>();
void addPath(URL url) {
JarResource resource = null;
try {
//
if(url.getProtocol().equals("file")) {
File fileDir = new File(url.toURI());
if(fileDir.isDirectory()) {
synchronized(classPathDirs) {
classPathDirs.add(fileDir.getAbsolutePath());
}
return;
} else if(fileDir.isFile()) {
try {
resource = factory.create(fileDir);
} catch(IOException eat) {
}
}else {
return;
}
}else if(url.toString().endsWith("/") || url.getPath().isEmpty()) {
synchronized(classPathDirs) {
classPathDirs.add(url.toString());
}
return;
}
if(resource == null) {
try {
resource = factory.create(url);
} catch(ZipException e) {
throw new ZipException(e.getMessage() + ": " + url);
}
}
String resourceName = resource.getName();
Set seenSet = new TreeSet<>();
Enumeration entries = resource.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String dirName = null;
boolean isToplevelFile = false;
String entryName = entry.getName();
// Remove potentially initial '/'
while (entryName.startsWith("/"))
entryName = entryName.substring(1);
if (entry.isDirectory()) {
if (entryName.endsWith("/"))
dirName = entryName.substring(0, entryName.length() - 1); // canonicalize
else
dirName = entryName;
} else {
int slashPos = entryName.lastIndexOf("/");
if (slashPos > 0)
dirName = entryName.substring(0, slashPos); // isolate directory part
else
isToplevelFile = true; // dirName will be null; there is no directory part
}
// Add all parent directories "foo/bar/dir1/dir2", "foo/bar/dir1", "foo/bar", "foo"
while (dirName != null) {
// optimization: if we saw the long nested path (then we already processed its parents as well)
if (seenSet.contains(dirName))
break;
seenSet.add(dirName);
synchronized(cache) {
cache.computeIfAbsent(dirName, newSetFactory).add(resourceName);
}
int slashPos = dirName.lastIndexOf("/");
if (slashPos > 0)
dirName = dirName.substring(0, slashPos);
else
dirName = null;
}
if (isToplevelFile) {
if (!seenSet.contains("")) {
seenSet.add("");
synchronized(cache) {
cache.computeIfAbsent("", newSetFactory).add(resourceName);
}
}
}
}
// Add root dir for all jar files (even empty ones)
if (!seenSet.contains("")) {
seenSet.add("");
// Add root dir for all jar files (even empty ones)
synchronized(cache) {
cache.computeIfAbsent("", newSetFactory).add(resourceName);
}
}
} catch (Exception e) {
} finally {
if (resource != null) {
resource.put();
resource = null;
}
}
}
void removePath(URL url) {
JarResource resource = null;
try {
//
if(url.getProtocol().equals("file")) {
File fileDir = new File(url.toURI());
if(fileDir.isDirectory()) {
removeImpl(fileDir.getAbsolutePath());
return;
} else if(fileDir.isFile()) {
try {
resource = factory.create(fileDir);
} catch(IOException eat) {
}
}else {
return;
}
}else if(url.toString().endsWith("/") || url.getPath().isEmpty()) {
removeImpl(url.toString());
return;
}
if(resource == null) {
try {
resource = factory.create(url);
} catch(ZipException e) {
}
}
if(resource != null) {
removeImpl(resource.getName());
}else {
removeImpl(url.toString());
}
} catch (Exception e) {
removeImpl(url.toString());
} finally {
if (resource != null) {
resource.put();
resource = null;
}
}
}
private void removeImpl(String jarFileName) {
synchronized(cache) {
for(String key : new ArrayList<>(cache.keySet())) {
Set entries = cache.get(key);
if(entries!=null) {
entries.remove(jarFileName);
if(entries.isEmpty()) {
cache.remove(key);
}
}else {
cache.remove(key);
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy