001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.core.util; 017 018import java.io.File; 019import java.io.IOException; 020import java.net.JarURLConnection; 021import java.net.URI; 022import java.net.URL; 023import java.net.URLConnection; 024import java.nio.file.FileSystem; 025import java.nio.file.FileSystems; 026import java.util.Collections; 027import java.util.HashMap; 028import java.util.Map; 029 030/** 031 * This component centralize the access to zip files 032 * Beware: All opened zip files are kept opened in memory 033 */ 034public final class JarFSManager 035{ 036 private static JarFSManager _instance; 037 038 private Map<String, FileSystem> _openedFS = new HashMap<>(); 039 040 private JarFSManager() 041 { 042 // private 043 } 044 045 /** 046 * Get the unique instance 047 * @return the unique instance 048 */ 049 public static JarFSManager getInstance() 050 { 051 if (_instance == null) 052 { 053 _instance = new JarFSManager(); 054 } 055 056 return _instance; 057 } 058 059 /** 060 * Return the jar filesystem associated with the given resource 061 * @param resourcePath The resource path to seek. Such as 'org/apache/ivy/logo.png'. 062 * @return The JAR filesystem or null if the resource cannot be found 063 * @throws IOException If an error occurred while getting the JAR file of an existing resource 064 */ 065 public FileSystem getFileSystemByResource(String resourcePath) throws IOException 066 { 067 String uri = getJARFileURI(resourcePath); 068 return getFileSystemByURI(uri); 069 } 070 071 /** 072 * Return the jar filesystem associated with the given jar file 073 * @param jarFile the jar file to open 074 * @return The JAR filesystem or null if the file has a problem 075 * @throws IOException If an error occurred while opening the JAR file 076 */ 077 public FileSystem getFileSystemByFile(File jarFile) throws IOException 078 { 079 String uri = "jar:" + jarFile.getCanonicalFile().toURI().toString(); 080 return getFileSystemByURI(uri); 081 } 082 083 /** 084 * Determine the JAR file holding the given resource 085 * @param resourcePath The resource path to seek. Such as 'org/apache/ivy/logo.png'. 086 * @return The JAR file location. Such as '/path/to/jar/ivy.jar' or null if the resource cannot be found 087 * @throws IOException If an error occurred while getting the JAR file of an existing resource 088 */ 089 public String getJARFileURI(String resourcePath) throws IOException 090 { 091 URL resource = getClass().getClassLoader().getResource(resourcePath); 092 if (resource == null) 093 { 094 return null; 095 } 096 097 URLConnection connection = resource.openConnection(); 098 URL jarFileURL = ((JarURLConnection) connection).getJarFileURL(); 099 return "jar:" + jarFileURL.toString(); 100 } 101 102 /** 103 * Return the jar filesystem associated with the given jar file denoted by its URI 104 * @param jarURI Such as "jar:file:/path/to/file.jar" 105 * @return The filesystem or null if the jarURI is null 106 * @throws IOException If the JAR file cannot be opened correctly 107 */ 108 public synchronized FileSystem getFileSystemByURI(String jarURI) throws IOException 109 { 110 if (jarURI == null) 111 { 112 return null; 113 } 114 115 return _openedFS.computeIfAbsent(jarURI, LambdaUtils.wrap(u -> FileSystems.newFileSystem(new URI(u), Collections.emptyMap()))); 116 } 117}