JNLP loads Sigar native libs via file: but not http: - java

I have an app that is using jnlp as the launcher. It uses the Sigar libraries which require dynamically loaded native libraries for platform specific code.
For purposes of debugging this I have two JNLP files, one that references the codebase using file: urls and the other using http: urls. The http urls point to localhost apache which is properly serving the files. I can watch JNLP download them during its launch sequence via apache logs so I know the files are getting to my app properly.
Here are the two codebase tags
codebase="file:/Users/siberian/Documents/workspace_mnis/MNIS/localhost/"
href="file:/Users/siberian/Documents/workspace_mnis/MNIS/localhost/minis.jnlp"-->
and
codebase="http://localhost/"
href="http://localhost/mnis.jnlp"
If I double click the file: version it works fine. If I load it via my browser it works fine.
If I double click or browser load the http: version it fails to find the dynamic libraries with this error:
JNLPClassLoader: Finding library liblibsigar-universal64-macosx.dylib.dylib
[AWT-EventQueue-0] DEBUG Sigar - no libsigar-universal64-macosx.dylib in java.library.path
org.hyperic.sigar.SigarException: no libsigar-universal64-macosx.dylib in java.library.path
Now, the interesting to note is that file that it says it cant find
liblibsigar-universal64-macosx.dylib.dylib
Note the prefix extra 'lib' and postfix extra '.dylib'.
There are notes on the Sigar/vmware forums about similar problems with no solutions.
The core question is, why is this acting differently in a file: context vs an http: context?
Also of note, I have unsigned and resigned all of my files, there are no signature errors that I can see.
There are hints at an answer here: Java Webstart with Tibco Native Libs
But it works in a file: context which makes me think something else is wrong.
Also: JaNeLa tells me all is fine

JNLP and Sigar classloaders do not play well together. This was pieced together but works well in both Windows and Mac environments. The VMWare forums HINT at an answer like this but no one has put it all together. For JNLP you need to specifically do a loadLibrary based on your architecture. In a non-JNLP context Sigar handles this transparently but JNLP breaks that somehow, requiring this manual platform selection.
Just put this method into your class and call it BEFORE you call new Sigar() and it should work properly. This solutions requires the commons-lang library. You can easily extend this for linux and other alternate platform support.
private static void preloadSigar() {
String arch = System.getProperty("os.arch");
String libName;
if (SystemUtils.IS_OS_WINDOWS) {
if (arch.equalsIgnoreCase("x86"))
libName = "sigar-x86-winnt";
else
libName = "sigar-amd64-winnt";
} else if (SystemUtils.IS_OS_MAC_OSX) {
if (arch.startsWith("i") && arch.endsWith("86"))
libName = "sigar-universal-macosx";
else
libName = "sigar-universal64-macosx";
} else {
throw new RuntimeException("Unrecognized platform!");
}
System.setProperty("org.hyperic.sigar.path", "-");
System.loadLibrary(libName);
}

Related

Mac app cannot run due to gatekeeper block jna*.tmp file generated at launch time

My app has already been signed and notarized successfully, but I got this error while trying to launch the app:
"jna7223640233751603426.tmp" cannot be opened because the developer cannot be verified
Does anybody have the solution for this?
How can I fix this problem? Can I block the file created while launching the app or make it valid for the Gatekeeper?
JNA releases have small precompiled binary JARs for each of its supported operating system/architecture combinations. These are not signed, although the source code is available if you wish to build and sign them yourself.
From a conversation on the JNA mailing list:
MacOS does not allow code created at runtime (which is typical malware behaviour), and that extracting a library at runtime looks like that code was created because it’s not visible outside the jar file in which it came.
A solution listed in that thread is:
by pre-extracting the library and bundling it as part of the installer.
In addition to this, you'll need to configure your application to tell JNA not to extract its own library but to use the one which you have signed and extracted as part of your installer. Source code from the above email thread:
boolean sandboxed = System.getenv("APP_SANDBOX_CONTAINER_ID") != null;
// Some 3rd party apps install to the system and can cause crashes
System.setProperty("jna.nosys", "true");
if(sandboxed) {
// Don't unpack the libraries
System.setProperty("jna.nounpack", "true");
// Tell JNA where the native libraries are
System.setProperty("jna.boot.library.path", "<path to native libs>");
}

"jar:file" vs. only "file:" reference when retrieving resources in Java

This question is related to my question
Jetty 11.0.11 - 404 on html file in \src\main\webapp\static - maven embedded fat jar
What --EXACTLY-- does "jar:file" mean as a Java resource reference, vs. just "file:"?
And how is that influenced by the operating system ran under?
E. g. using this resource reference in Jetty webserver, in Windows with Oracle JDK 17, files are found as resources and parsed by Jetty webserver:
file:///D:/Projects/verdi_2/target/classes/static/,AVAILABLE}{file:/D:/Projects/verdi_2/target/classes/static}
Using this resource reference in Jetty webserver, in Ubuntu Linux 20.04 LTS with Oracle JDK 17, NO files are found and nothing can be parsed by Jetty webserver:
jar:file:/usr/src/verdi/verdi-12-JDK17-jar-with-dependencies.jar!/static
Is there a difference in how a Linux version of JDK interprets "jar:file" vs. how a Windows version of the JDK interprets "jar:file"?
EDIT: The related issue is the Jetty webserver apparently can no longer serve resources directly out of a JAR file it is itself embedded in. This is now a GitHub bug ticket at https://github.com/eclipse/jetty.project/issues/8549
file: is the beginning of a general file url. jar:file: is that for a jar file particularly, with a view to referring (usually) to a particular entry in a jar. Here's an example you can run (obviously with your own jar url) where you can save an entry as a file (given by the parameter to the app)
import java.nio.file.Paths;
import java.nio.file.Files;
import java.net.URL;
public class JarUrl {
public static void main(String[] args) {
try {
URL url = new URL("jar:file:root.jar!/root/a/b.txt");
Files.copy(url.openStream(), Paths.get(args[0]));
}
catch(Throwable t) {
t.printStackTrace();
}
}
}
What --EXACTLY-- does "jar:file" mean as a Java resource reference, vs. just "file:"?
You're mischaracterising the URL a little bit. The string until the first : decides the 'scheme' of a URL, so, the pertinent question is: How does jar: work. The file: part is a smaller aspect of a sub-part of the jar bit.
How does jar: work
The format is jar:(URL-of-jar)!(path-inside-jar)
Where URL-of-jar is itself a valid URL (and file: is just one way to do that. So is http, for that matter), and path-inside-jar is not a URL but a path.
The meaning is: First, resolve the 'URL-of-jar' URL. This gets you a jar file. Then, open the jar file, and retrieve the resource at the stated path.
So, to pull this one apart:
jar:file:/usr/src/verdi/verdi-12-JDK17-jar-with-dependencies.jar!/static
The jar is located at URL file:/usr/src/verdi/verdi-12-JDK17-jar-with-dependencies.jar and the resource it is referring to is the /static resource inside the jar found at the given URL.
How does file: work
That's not java-specific; file: is a generally available URL scheme. You can even type it in a web browser. The more general URL formatting scheme is scheme://server/resource, but with file:, server doesn't apply (it is by definition local to the system you are on), so usually its put as file:///foo, i.e. - an empty 'server' part. Because 3 slashes is a drag to type, I guess, file:/resource is allowed by some 'URL parsers', including java's in this regard, so, file:/usr/... simply maps straight to a local folder: /usr/src/verdi/verdi-12-JDK-etc, as in, if you type ls /usr/src/verdi/verdi-12-JDK17-jar-with-dependencies.jar on the command line on your system, it would show a result (and if it does not, this URL would fail to find anything).
And how is that influenced by the operating system ran under?
It isn't. file URLs are a general concept that work on any platform. Of course, /usr/src/verdi/etc is never going to work correctly on a windows platform. Or on anybody else's machine. The problem isn't "Oh no! This won't run on another OS!". The problem with file URLs, especially absolute ones, is "Oh no! This will not run on any machine other than this one!".
file:///D:/Projects
I've explained the triple slashes earlier. This is the standard windows 'scheme' for how to stick paths in file URLs: Always forward slashes (even though windows normally uses backslashes), and treat the disk letter as if it is a 'drive' in the 'root': /D:/Project is URL-ese for:
D:
cd \Project
There is no difference in OS at all - file: URLs are handled by 'interpret this file URL the way any file URL would be interpreted on this machine'.
The answer to the related question
Jetty 11.0.11 - 404 on html file in \src\main\webapp\static - maven embedded fat jar
which prompted this post is in the long series of posts beneath this GitHub issue for jetty:
https://github.com/eclipse/jetty.project/issues/8549
In essence, eventually I had to first clean up my Maven pom.xml (see this thread for the discussion and for links to a pom.xml example that is compliant with Maven Shade plugin and Jetty 11.0.11 requirements and standards) then at the end of the day hardcode a link to the JAR file to find the HTML, JS, etc. resources Jetty was to serve out as a webpage. Also put in a conditional where, on compiling, I need to specify if the code will run "in-IDE" (in my case, Netbeans 14) or "in-JAR" - e. g. in a detached JRE elsewhere than the Netbeans 14 IDE.
Also dropped using the Jetty WebAppContext class and started rendering web content out of a normal ServletContextHandler.
Hopefully this may help someone upgrading Jetty from Jetty 9.xxx to 11 and finding that it all falls apart.
For details as to why they changed so much, see the GitHub link (the last few entries are apropos.)
The github discussion also contains full working source code (startJettyc method) that solved the issue of getting a 404 in a detached, non-IDE modality where the JAR was being run in an JRE separate from an IDE.
Stefan

Java JNA load DLL

I have a problem when I try load a DLL like this:
String a = "C:\\Users\\ElteGps 022\\Documents\\NetBeansProjects\\JavaApplication1\\src\\lib\\EQ2008_Dll.dll";
String strDllFileName = m_strUserPath + "\\res\\EQ2008_Dll.dll";
String strEQ2008_Dll_Set_Path = m_strUserPath + "\\res\\EQ2008_Dll_Set.ini";
m_DllLibrary = (DllLibrary) Native.loadLibrary(a,DllLibrary.class);
I see this:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'C:\Users\ElteGps 022\Documents\NetBeansProjects\JavaApplication1\src\lib\EQ2008_Dll.dll': Nie mo¿na odnaleæ okrelonego modu³
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:163)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:236)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:379)
at com.sun.jna.Native.loadLibrary(Native.java:364)
at javaapplication1.Fun.main(Fun.java:280)
I read and I did this:
Can not add all the classes files from the JNI folder in Eclipse (JAVA, Windows 7)
giving 'java.library.path' in netbeans for .dll/.so files
From the JNA javadoc
Library Search Paths
A search for a given library will scan the following locations:
jna.library.path User-customizable path
jna.platform.library.path Platform-specific
paths On OSX, ~/Library/Frameworks,
/Library/Frameworks, and
/System/Library/Frameworks will be searched for a
framework with a name corresponding to that requested. Absolute
paths to frameworks are also accepted, either ending at the framework
name (sans ".framework") or the full path to the framework shared
library (e.g. CoreServices.framework/CoreServices).
Context class loader classpath. Deployed native libraries
may be installed on the classpath under
${os-prefix}/LIBRARY_FILENAME, where
${os-prefix} is the OS/Arch prefix returned by Platform.getNativeLibraryResourcePrefix().
If bundled in a jar file, the resource will be extracted to
jna.tmpdir for loading, and later removed (but only if
jna.nounpack is false or not set). You may
set the system property jna.debug_load=true to make JNA
print the steps of its library search to the console.
Native.loadLibrary doesn't work with a full path, try instead System.load
If you can't use that you could also specify the directory of the dll before the loading by setting the enviroment variable of java like this
System.setProperty("jna.library.path", "C:\\Users\\ElteGps 022\\Documents\\NetBeansProjects\\JavaApplication1\\src\\lib");
But this is higly not recommended since it will works only on your computer

ImageMagick/IM4J FileNotFoundException

I am trying to use IM4J (a Java wrapper for ImageMagick) to create thumbnails of JPEGs and it is my first experience (ever) with both libraries. Please note that this is a hard requirement handed to me by my tech lead (so please don't suggest to use anything other than an IM4J/ImageMagick) solution - my hands are tied on the technology choice here!
I am getting a FileNotFoundException on the and convert command which tells me I don't have one of these libraries (or both) setup correctly.
On my computer, here is my directory structure:
C:/
myApp/
images/ --> where all of my JPEGs are
thumbnails/ --> where I want ImageMagick to send the converted thumbnails to
imageMagickHome/ --> Where I downloaded the DLL to
ImageMagick-6.7.6-1-Q16-windows-dll.exe
...
In my Java project, I make sure that the IM4J JAR (im4java-1.2.0.jar) is on the classpath at runtime. Although I am required to use the 1.2.0 version of IM4J, I have the liberty to use any version of ImageMagick that I want. I simply chose this version because it seemed like the most current/stable version for my Windows 7 (32-bit) machine. If I should use a different version, please send me a link to it from the ImageMagick downloads page in your answer!
As for ImageMagick, I just downloaded that EXE from here and placed it in the folder mentioned above - I didn't do any installation, wizard, MSI, environment variable configuration, etc.
Then, in my Java code:
// In my driver...
File currentFile = new File("C:/myApp/images/test.jpg"); --> exists and is sitting at this location
File thumbFile = new File("C:/myApp/thumbnails/test-thumb.jpg"); --> doesnt exist yet! (destination file)
Thumbnailer myThumbnailer = new Thumbnailer();
myThumbnailer.generateThumbnail(currentFile, thumbFile);
// Then the Thumbnailer:
public class Thumbnailer
{
// ... omitted for brevity
public void generateThumbnail(File originalFile, File thumbnailFile)
{
// Reads appConfig.xml from classpath, validates it against a schema,
// and reads the contents of an element called <imPath> into this
// method's return value. See below
String imPath = getIMPathFromAppConfigFile();
org.im4java.core.IMOperation op = new Operation();
op.colorspace(this.colorSpace);
op.addImage(originalFile.getAbsolutePath());
op.flatten();
op.addImage(thumbnailFile.getAbsolutePath());
ConvertCmd cmd = new ConvertCmd();
cmd.setSearchPath(imPath);
// This next line is what throws the FileNotFoundException
cmd.run(op);
}
}
The section of my appConfig.xml file that contains the imPath:
<imPath>C:/myApp/imageMagickHome</imPath>
Please note - if this appConfig.xml is not well-formed, our schema validator will catch it. Since we are not getting schema validation errors, we can rule this out as a culprit. However, notice my file path delimiters; they are all forward slashes. I did this because I was told that, on Windows systems, the forward slash is treated the same as a *nix backslash, in reference to file paths. Believe it or not, we are developing on Windows
machines, but deploying to linux servers, so this was my solution (again, not my call!).
IM4J even acknowledges that Windows users can have trouble sometimes and explains in this article that Windows developers might have to set an IM4JAVA_TOOLPATH env var to get this library to work. I tried this suggestion, created a new System-wide environmental variable of the same name and set its value to C:\myApp\imageMagickHome. Still no difference. But notice here I am using backslashes. This is because this env var is local to my machine, whereas the appConfig.xml is a config descriptor that gets deployed to the linux servers.
From what I can tell, the culprit is probably one (or more) of the following:
I didn't "install" the ImageMagick EXE correctly and should have used an installer/MSI; or I need to add some other environmental variables for ImageMagick (not IM4J) itself
Perhaps I still don't have IM4J configured correctly and need to add more environmental variables
Could be the Windows/*nix "/" vs. "" issue from my appConfig.xml file as mentioned above
I'm also perplexed as to why I'm getting a FileNotFoundException on a file named "convert":
java.io.FileNotFoundException: convert
I assume this is a batch/shell file living somewhere inside the IM4J jar (since the only thing I downloaded for ImageMagick was the EXE). However, if I extract the IM4J jar I only see classes inside of it. I see "script generator" classes, so I assume these kick off before my cmd.run(op) call and create the convert file, and maybe that's what I'm missing (perhaps I need to manually kick off one of these generators, like CmdScriptGenerator prior to executing my Thumbnailer methods. . Or, maybe my download is incomplete.
Either way, I'm just not versed enough with either library to know where to start.
Thanks for any help with this.
Run the 'ImageMagick-6.7.6-1-Q16-windows-dll.exe' installer first to install the imagemagick libraries. Then make sure your environment path includes the location of the installed binaries ('convert.exe', 'mogrify.exe', etc)
Make sure u have Set the environment-variable IM4JAVA_TOOLPATH.

java.lang.UnsatisfiedLinkError no *****.dll in java.library.path

How can I load a custom dll file in my web application? I've tried the following:
Copied all required dlls in system32 folder and tried to load one of them in Servlet constructor System.loadLibrary
Copied required dlls into tomcat_home/shared/lib and tomcat_home/common/lib
All these dlls are in WEB-INF/lib of the web-application
In order for System.loadLibrary() to work, the library (on Windows, a DLL) must be in a directory somewhere on your PATH or on a path listed in the java.library.path system property (so you can launch Java like java -Djava.library.path=/path/to/dir).
Additionally, for loadLibrary(), you specify the base name of the library, without the .dll at the end. So, for /path/to/something.dll, you would just use System.loadLibrary("something").
You also need to look at the exact UnsatisfiedLinkError that you are getting. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path
then it can't find the foo library (foo.dll) in your PATH or java.library.path. If it says something like:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
then something is wrong with the library itself in the sense that Java is not able to map a native Java function in your application to its actual native counterpart.
To start with, I would put some logging around your System.loadLibrary() call to see if that executes properly. If it throws an exception or is not in a code path that is actually executed, then you will always get the latter type of UnsatisfiedLinkError explained above.
As a sidenote, most people put their loadLibrary() calls into a static initializer block in the class with the native methods, to ensure that it is always executed exactly once:
class Foo {
static {
System.loadLibrary('foo');
}
public Foo() {
}
}
Changing 'java.library.path' variable at runtime is not enough because it is read only once by JVM. You have to reset it like:
System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);
Please, take a loot at: Changing Java Library Path at Runtime.
The original answer by Adam Batkin will lead you to a solution, but if you redeploy your webapp (without restarting your web container), you should run into the following error:
java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
at java.lang.Runtime.load0(Runtime.java:787)
at java.lang.System.load(System.java:1022)
This happens because the ClassLoader that originally loaded your DLL still references this DLL. However, your webapp is now running with a new ClassLoader, and because the same JVM is running and a JVM won't allow 2 references to the same DLL, you can't reload it. Thus, your webapp can't access the existing DLL and can't load a new one. So.... you're stuck.
Tomcat's ClassLoader documentation outlines why your reloaded webapp runs in a new isolated ClassLoader and how you can work around this limitation (at a very high level).
The solution is to extend Adam Batkin's solution a little:
package awesome;
public class Foo {
static {
System.loadLibrary('foo');
}
// required to work with JDK 6 and JDK 7
public static void main(String[] args) {
}
}
Then placing a jar containing JUST this compiled class into the TOMCAT_HOME/lib folder.
Now, within your webapp, you just have to force Tomcat to reference this class, which can be done as simply as this:
Class.forName("awesome.Foo");
Now your DLL should be loaded in the common classloader, and can be referenced from your webapp even after being redeployed.
Make sense?
A working reference copy can be found on google code, static-dll-bootstrapper .
You can use System.load() to provide an absolute path which is what you want, rather than a file in the standard library folder for the respective OS.
If you want native applications that already exist, use System.loadLibrary(String filename). If you want to provide your own you're probably better with load().
You should also be able to use loadLibrary with the java.library.path set correctly. See ClassLoader.java for implementation source showing both paths being checked (OpenJDK)
In the case where the problem is that System.loadLibrary cannot find the DLL in question, one common misconception (reinforced by Java's error message) is that the system property java.library.path is the answer. If you set the system property java.library.path to the directory where your DLL is located, then System.loadLibrary will indeed find your DLL. However, if your DLL in turn depends on other DLLs, as is often the case, then java.library.path cannot help, because the loading of the dependent DLLs is managed entirely by the operating system, which knows nothing of java.library.path. Thus, it is almost always better to bypass java.library.path and simply add your DLL's directory to LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS), or Path (Windows) prior to starting the JVM.
(Note: I am using the term "DLL" in the generic sense of DLL or shared library.)
If you need to load a file that's relative to some directory where you already are (like in the current directory), here's an easy solution:
File f;
if (System.getProperty("sun.arch.data.model").equals("32")) {
// 32-bit JVM
f = new File("mylibfile32.so");
} else {
// 64-bit JVM
f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());
For those who are looking for java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path
I was facing same exception; I tried everything and important things to make it work are:
Correct version of pdf lib.jar ( In my case it was wrong version jar kept in server runtime )
Make a folder and keep the pdflib jar in it and add the folder in your PATH variable
It worked with tomcat 6.
If you believe that you added a path of native lib to %PATH%, try testing with:
System.out.println(System.getProperty("java.library.path"))
It should show you actually if your dll is on %PATH%
Restart the IDE Idea, which appeared to work for me after I setup the env variable by adding it to the %PATH%
The issue for me was naming:
The library name should begin with "lib..." such as libnative.dll.
So you might think you need to load "libnative": System.loadLibrary("libnative")
But you actually need to load "native": System.loadLibrary("native")
Poor me ! spent a whole day behind this.Writing it down here if any body replicates this issue.
I was trying to load as Adam suggested but then got caught with AMD64 vs IA 32 exception.If in any case after working as per Adam's(no doubt the best pick) walkthrough,try to have a 64 bit version of latest jre.Make sure your JRE AND JDK are 64 bit and you have correctly added it to your classpath.
My working example goes here:unstatisfied link error
I'm using Mac OS X Yosemite and Netbeans 8.02, I got the same error and the simple solution I have found is like above, this is useful when you need to include native library in the project. So do the next for Netbeans:
1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok
I hope it could be useful for someone.
The link where I found the solution is here:
java.library.path – What is it and how to use
It is simple just write java -XshowSettings:properties on your command line in windows and then paste all the files in the path shown by the java.library.path.
I had the same problem and the error was due to a rename of the dll.
It could happen that the library name is also written somewhere inside the dll.
When I put back its original name I was able to load using System.loadLibrary
First, you'll want to ensure the directory to your native library is on the java.library.path. See how to do that here. Then, you can call System.loadLibrary(nativeLibraryNameWithoutExtension) - making sure to not include the file extension in the name of your library.

Categories

Resources