28import java.io.BufferedInputStream;
29import java.io.BufferedOutputStream;
31import java.io.FileOutputStream;
32import java.io.IOException;
33import java.io.InputStream;
34import java.io.OutputStream;
35import java.net.JarURLConnection;
36import java.net.URISyntaxException;
38import java.net.URLConnection;
39import java.security.cert.Certificate;
40import java.util.Enumeration;
41import java.util.HashMap;
43import java.util.jar.JarEntry;
44import java.util.jar.JarFile;
46import org.jau.io.IOUtil;
47import org.jau.net.Uri;
48import org.jau.sec.SecurityUtil;
49import org.jau.sys.Debug;
50import org.jau.sys.JNILibrary;
51import org.jau.sys.PlatformProps;
52import org.jau.sys.PlatformTypes;
55 private static final boolean DEBUG =
Debug.
debug(
"JarUtil");
57 private static final int BUFFER_SIZE = 4096;
86 @SuppressWarnings({
"removal" })
87 public static void setResolver(
final Resolver r)
throws IllegalArgumentException, IllegalStateException, SecurityException {
89 throw new IllegalArgumentException(
"Null Resolver passed");
92 if(resolver !=
null) {
93 throw new IllegalStateException(
"Resolver already set!");
97 if(security !=
null) {
98 security.checkSetFactory();
117 public static boolean hasJarUri(
final String clazzBinName,
final ClassLoader cl) {
119 return null !=
getJarUri(clazzBinName, cl);
120 }
catch (
final Exception e) { }
140 public static Uri getJarUri(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
141 if(
null == clazzBinName ||
null == cl) {
142 throw new IllegalArgumentException(
"null arguments: clazzBinName "+clazzBinName+
", cl "+cl);
148 final String scheme = url.getProtocol();
149 if(
null != resolver &&
155 final URL _url = resolver.resolve( url );
158 System.err.println(
"getJarUri Resolver: "+url+
"\n\t-> "+_url+
"\n\t-> "+uri);
163 System.err.println(
"getJarUri Default "+url+
"\n\t-> "+uri);
168 throw new IllegalArgumentException(
"Uri is not using scheme "+
Uri.
JAR_SCHEME+
": <"+uri+
">");
171 System.err.println(
"getJarUri res: "+clazzBinName+
" -> "+url+
" -> "+uri);
191 if(
null == classJarUri) {
192 throw new IllegalArgumentException(
"Uri is null");
194 if( !classJarUri.isJarScheme() ) {
195 throw new IllegalArgumentException(
"Uri is not using scheme "+
Uri.
JAR_SCHEME+
": <"+classJarUri+
">");
205 ssp = ssp.substring(0, idx);
207 throw new IllegalArgumentException(
"Uri does not contain jar uri terminator '!', in <"+classJarUri+
">");
214 idx = ssp.lastIndexOf(
'/');
217 idx = ssp.lastIndexOf(
':');
219 throw new IllegalArgumentException(
"Uri does not contain protocol terminator ':', in <"+classJarUri+
">");
222 ssp = ssp.substring(idx+1);
224 if(0 >= ssp.lastIndexOf(
".jar")) {
225 throw new IllegalArgumentException(
"No Jar name in <"+classJarUri+
">");
228 System.err.println(
"getJarName res: "+ssp);
249 public static Uri.Encoded getJarBasename(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
263 if(
null == classJarUri) {
264 throw new IllegalArgumentException(
"Uri is null");
267 throw new IllegalArgumentException(
"Uri is not a using scheme "+
Uri.
JAR_SCHEME+
": <"+classJarUri+
">");
280 System.err.println(
"getJarEntry res: "+classJarUri+
" -> "+uriSSP+
" -> "+idx+
" -> "+res);
284 throw new IllegalArgumentException(
"JAR Uri does not contain jar uri terminator '!', uri <"+classJarUri+
">");
304 public static Uri getJarFileUri(
final String clazzBinName,
final ClassLoader cl)
throws IllegalArgumentException, IOException, URISyntaxException {
305 if(
null == clazzBinName ||
null == cl) {
306 throw new IllegalArgumentException(
"null arguments: clazzBinName "+clazzBinName+
", cl "+cl);
311 System.err.println(
"getJarFileUri res: "+uri);
324 if(
null == baseUri ||
null == jarFileName) {
325 throw new IllegalArgumentException(
"null arguments: baseUri "+baseUri+
", jarFileName "+jarFileName);
336 public static Uri getJarFileUri(
final Uri jarSubUri)
throws IllegalArgumentException, URISyntaxException {
337 if(
null == jarSubUri) {
338 throw new IllegalArgumentException(
"jarSubUri is null");
350 if(
null == jarSubUriS) {
351 throw new IllegalArgumentException(
"jarSubUriS is null");
364 if(
null == jarEntry) {
365 throw new IllegalArgumentException(
"jarEntry is null");
367 return Uri.
cast(jarFileUri.toString()+jarEntry);
379 public static JarFile
getJarFile(
final String clazzBinName,
final ClassLoader cl)
throws IOException, IllegalArgumentException, URISyntaxException {
390 public static JarFile
getJarFile(
final Uri jarFileUri)
throws IOException, IllegalArgumentException, URISyntaxException {
391 if(
null == jarFileUri) {
392 throw new IllegalArgumentException(
"null jarFileUri");
395 System.err.println(
"getJarFile.0: "+jarFileUri.toString());
397 final URL jarFileURL = jarFileUri.toURL();
399 System.err.println(
"getJarFile.1: "+jarFileURL.toString());
401 final URLConnection urlc = jarFileURL.openConnection();
402 if(urlc instanceof JarURLConnection) {
403 final JarURLConnection jarConnection = (JarURLConnection)jarFileURL.openConnection();
404 final JarFile jarFile = jarConnection.getJarFile();
406 System.err.println(
"getJarFile res: "+jarFile.getName());
411 System.err.println(
"getJarFile res: NULL");
448 public static Uri getRelativeOf(
final Class<?> classFromJavaJar,
final Uri.
Encoded cutOffInclSubDir,
final Uri.
Encoded relResPath)
throws IllegalArgumentException, IOException, URISyntaxException {
449 final ClassLoader cl = classFromJavaJar.getClassLoader();
452 System.err.println(
"JarUtil.getRelativeOf: "+
"(classFromJavaJar "+classFromJavaJar+
", classJarUri "+classJarUri+
453 ", cutOffInclSubDir "+cutOffInclSubDir+
", relResPath "+relResPath+
"): ");
457 if(
null == jarSubUri) {
458 throw new IllegalArgumentException(
"JarSubUri is null of: "+classJarUri);
462 System.err.println(
"JarUtil.getRelativeOf: "+
"uri "+jarSubUri.
toString()+
" -> "+jarUriRoot);
466 if( jarUriRoot.endsWith(cutOffInclSubDir.get()) ) {
467 resUri = jarUriRoot.concat(relResPath);
469 resUri = jarUriRoot.concat(cutOffInclSubDir).concat(relResPath);
472 System.err.println(
"JarUtil.getRelativeOf: "+
"... -> "+resUri);
477 System.err.println(
"JarUtil.getRelativeOf: "+
"fin "+resJarUri);
487 System.err.println(
"JarUtil: getNativeLibNames: "+jarFile);
490 final Map<String,String> nameMap =
new HashMap<String, String>();
491 final Enumeration<JarEntry> entries = jarFile.entries();
493 while (entries.hasMoreElements()) {
494 final JarEntry entry = entries.nextElement();
495 final String entryName = entry.getName();
498 if(
null != baseName) {
499 nameMap.put(baseName, entryName);
541 public static final int extract(
final File dest,
final Map<String, String> nativeLibMap,
542 final JarFile jarFile,
543 final String nativeLibraryPath,
544 final boolean extractNativeLibraries,
545 final boolean extractClassFiles,
final boolean extractOtherFiles)
throws IOException {
548 System.err.println(
"JarUtil: extract: "+jarFile.getName()+
" -> "+dest+
549 ", extractNativeLibraries "+extractNativeLibraries+
" ("+nativeLibraryPath+
")"+
550 ", extractClassFiles "+extractClassFiles+
551 ", extractOtherFiles "+extractOtherFiles);
555 final Enumeration<JarEntry> entries = jarFile.entries();
556 while (entries.hasMoreElements()) {
557 final JarEntry entry = entries.nextElement();
558 final String entryName = entry.getName();
562 final boolean isNativeLib =
null != libBaseName;
564 if(!extractNativeLibraries) {
566 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, skip all native libs");
570 if(
null != nativeLibraryPath) {
571 final String nativeLibraryPathS;
572 final String dirnameS;
574 nativeLibraryPathS =
IOUtil.
slashify(nativeLibraryPath,
false ,
true );
576 }
catch (
final URISyntaxException e) {
577 throw new IOException(e);
579 if( !nativeLibraryPathS.equals(dirnameS) ) {
581 System.err.println(
"JarUtil: JarEntry : " + entryName +
" native-lib skipped, not in path: "+nativeLibraryPathS);
588 final boolean isClassFile = entryName.endsWith(
".class");
589 if(isClassFile && !extractClassFiles) {
591 System.err.println(
"JarUtil: JarEntry : " + entryName +
" class-file skipped");
596 if(!isNativeLib && !isClassFile && !extractOtherFiles) {
598 System.err.println(
"JarUtil: JarEntry : " + entryName +
" other-file skipped");
603 final boolean isDir = entryName.endsWith(
"/");
605 final boolean isRootEntry = entryName.indexOf(
'/') == -1 &&
606 entryName.indexOf(File.separatorChar) == -1;
609 System.err.println(
"JarUtil: JarEntry : isNativeLib " + isNativeLib +
610 ", isClassFile " + isClassFile +
", isDir " + isDir +
611 ", isRootEntry " + isRootEntry );
614 final File destFile =
new File(dest, entryName);
617 System.err.println(
"JarUtil: MKDIR: " + entryName +
" -> " + destFile );
621 final File destFolder =
new File(destFile.getParent());
622 if(!destFolder.exists()) {
624 System.err.println(
"JarUtil: MKDIR (parent): " + entryName +
" -> " + destFolder );
628 final InputStream in =
new BufferedInputStream(jarFile.getInputStream(entry));
629 final OutputStream out =
new BufferedOutputStream(
new FileOutputStream(destFile));
637 boolean addedAsNativeLib =
false;
640 if (isNativeLib && ( isRootEntry || !nativeLibMap.containsKey(libBaseName) ) ) {
641 nativeLibMap.put(libBaseName, destFile.getAbsolutePath());
642 addedAsNativeLib =
true;
643 fixNativeLibAttribs(destFile);
647 System.err.println(
"JarUtil: EXTRACT["+num+
"]: [" + libBaseName +
" -> ] " + entryName +
" -> " + destFile +
": "+numBytes+
" bytes, addedAsNativeLib: "+addedAsNativeLib);
660 private final static void fixNativeLibAttribs(
final File file) {
665 final String fileAbsPath = file.getAbsolutePath();
667 fixNativeLibAttribs(fileAbsPath);
669 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - OK");
671 }
catch (
final Throwable t) {
673 System.err.println(
"JarUtil.fixNativeLibAttribs: "+fileAbsPath+
" - "+t.getClass().getSimpleName()+
": "+t.getMessage());
678 private native
static boolean fixNativeLibAttribs(String fname);
689 throws IOException, SecurityException {
692 System.err.println(
"JarUtil: validateCertificates: "+jarFile.getName());
695 if (rootCerts ==
null || rootCerts.length == 0) {
696 throw new IllegalArgumentException(
"Null certificates passed");
699 final byte[] buf =
new byte[1024];
700 final Enumeration<JarEntry> entries = jarFile.entries();
701 while (entries.hasMoreElements()) {
702 final JarEntry entry = entries.nextElement();
703 if( ! entry.isDirectory() && ! entry.getName().startsWith(
"META-INF/") ) {
705 validateCertificate(rootCerts, jarFile, entry, buf);
714 private static final void validateCertificate(
final Certificate[] rootCerts,
715 final JarFile jar,
final JarEntry entry,
final byte[] buf)
throws IOException, SecurityException {
718 System.err.println(
"JarUtil: validate JarEntry : " + entry.getName());
724 final InputStream is = jar.getInputStream(entry);
726 while (is.read(buf) > 0) { }
732 final Certificate[] nativeCerts = entry.getCertificates();
733 if (nativeCerts ==
null || nativeCerts.length == 0) {
734 throw new SecurityException(
"no certificate for " + entry.getName() +
" in " + jar.getName());
737 if( !SecurityUtil.equals(rootCerts, nativeCerts) ) {
738 throw new SecurityException(
"certificates not equal for " + entry.getName() +
" in " + jar.getName());
static URL getClassURL(final String clazzBinName, final ClassLoader cl)
static int copyStream2Stream(final InputStream in, final OutputStream out, final int totalNumBytes)
Copy the specified input stream to the specified output stream.
static String getDirname(String fname)
Returns unified '/' dirname including the last '/'.
static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash)
Immutable RFC3986 encoded string.
final int lastIndexOf(final int ch)
See String#lastIndexOf(int).
final Encoded substring(final int start)
See String#substring(int).
This class implements an immutable Uri as defined by RFC 2396.
Uri getDirectory()
Returns this Uri's directory Uri.
final String toString()
Returns the encoded input as String, never null, same as getEncoded().
final Encoded getEncoded()
Returns the encoded input, never null.
final Encoded schemeSpecificPart
Encoded scheme-specific-part, never null.
static final String HTTP_SCHEME
{@value}
final boolean isJarScheme()
Returns true, if this instance is a jar scheme, otherwise false.
static Uri cast(final String encodedUri)
Casts the given encoded String to a new Encoded instance used to create the resulting Uri instance vi...
final Uri getContainedUri()
If this instance's schemeSpecificPart contains a Uri itself, a sub-Uri, return schemeSpecificPart + #...
static Uri valueOf(final File file)
Creates a new Uri instance using the given File instance.
static final String FILE_SCHEME
{@value}
static final String JAR_SCHEME
{@value}
static final String HTTPS_SCHEME
{@value}
static final char JAR_SCHEME_SEPARATOR
A JAR sub-protocol is separated from the JAR entry w/ this separator {@value}.
static final char SCHEME_SEPARATOR
{@value}
static Uri getJarFileUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
static Uri getJarFileUri(final Uri baseUri, final Uri.Encoded jarFileName)
static Uri getJarUri(final String clazzBinName, final ClassLoader cl)
The Class's "com.jogamp.common.GlueGenVersion" Uri jar:sub_protocol:/some/path/gluegen-rt....
static JarFile getJarFile(final Uri jarFileUri)
static Uri.Encoded getJarBasename(final String clazzBinName, final ClassLoader cl)
The Class's com.jogamp.common.GlueGenVersion Uri jar:sub_protocol:/some/path/gluegen-rt....
static boolean hasJarUri(final String clazzBinName, final ClassLoader cl)
Returns true if the Class's "com.jogamp.common.GlueGenVersion" is loaded from a JarFile and hence has...
static Uri getJarFileUri(final Uri jarSubUri)
static void setResolver(final Resolver r)
Setting a custom Resolver instance.
static JarFile getJarFile(final String clazzBinName, final ClassLoader cl)
static Uri getRelativeOf(final Class<?> classFromJavaJar, final Uri.Encoded cutOffInclSubDir, final Uri.Encoded relResPath)
Locates the Jar file Uri of a given resource relative to a given class's Jar's Uri.
static final int extract(final File dest, final Map< String, String > nativeLibMap, final JarFile jarFile, final String nativeLibraryPath, final boolean extractNativeLibraries, final boolean extractClassFiles, final boolean extractOtherFiles)
Extract the files of the given jar file.
static final void validateCertificates(final Certificate[] rootCerts, final JarFile jarFile)
Validate the certificates for each native Lib in the jar file.
static Uri.Encoded getJarEntry(final Uri classJarUri)
The Class's Jar Uri jar:sub_protocol:/some/path/gluegen-rt.jar!
static Uri.Encoded getJarBasename(final Uri classJarUri)
The Class's Jar Uri jar:sub_protocol:/some/path/gluegen-rt.jar!
static Map< String, String > getNativeLibNames(final JarFile jarFile)
Return a map from native-lib-base-name to entry-name.
static Uri getJarFileUri(final Uri.Encoded jarSubUriS)
static Uri getJarEntryUri(final Uri jarFileUri, final Uri.Encoded jarEntry)
static final SecurityManager getSecurityManager()
Call wrapper for System#getSecurityManager().
Helper routines for logging and debugging.
static final boolean debug(final String subcomponent)
Static JNI Native Libraries handler.
static final String isValidNativeLibraryName(final String libName, final boolean isLowerCaseAlready)
Comparison of prefix and suffix of the given libName's basename is performed case insensitive
Interface allowing users to provide an URL resolver that will convert custom classloader URLs like Ec...