UnsatisfiedLinkError using Java Webstart with custom classloader

A

Andi

Hi,

I have a big problem to get my Application running on java webstart. I
have a custom classloader which will be used for some classes. Also I
need to load a dll which will be used by a native interface.

Here is my application entry point:

public class ApplicationStarter
{
public static void main(String[] args)
{
try
{
System.setSecurityManager(null);
CustomClassLoader classLoader = new
CustomClassLoader(Thread.currentThread().getContextClassLoader());
Thread.currentThread().setContextClassLoader(classLoader);

classLoader.loadClass("bugreport.jws6.Application").getMethod("main",
new Class[] { String[].class })
.invoke(null, new Object[] { args });
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

That all the classloading my classloader will be used I am calling the
real applcation per reflection loaded by my classloader.

Here the application I start:

public class Application
{
public static void main(String[] args)
{
try
{
System.loadLibrary("jws6-bugreport");
NativeInterface nativeInterface = new NativeInterface();
System.out.println("Native call result :" +
nativeInterface.doSomething());
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}

Here my Classloader:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

public class CustomClassLoader extends ClassLoader
{

private HashMap<String, Class<?>> loadedClasses = new
HashMap<String, Class<?>>();

public CustomClassLoader(ClassLoader parent)
{
super(parent);
}

public Class<?> customLoadClass(String name) throws
ClassNotFoundException
{
System.out.println("Custom loading of class " + name);
Class<?> clazz = this.loadedClasses.get(name);
if(clazz == null)
{
try
{
String classFilename = name.replace('.', '/') +
".class";

InputStream inputStream =
getResourceAsStream(classFilename);
if(inputStream == null)
throw new ClassNotFoundException(name);

ByteArrayOutputStream baout = new
ByteArrayOutputStream();
byte[] b = new byte[2048];
int byteCount;
while((byteCount = inputStream.read(b, 0, 2048)) !=
-1)
{
baout.write(b, 0, byteCount);
}
byte[] buffer = baout.toByteArray();
baout.close();

clazz = defineClass(name, buffer, 0, buffer.length);
this.loadedClasses.put(name, clazz);

}
catch (IOException e)
{
throw new ClassNotFoundException(name, e);
}
}

return clazz;
}

@Override
public Class<?> loadClass(String name) throws
ClassNotFoundException
{
Class<?> clazz;
if(name.startsWith("bugreport.jws6"))
{
clazz = customLoadClass(name);
}
else
{
clazz = super.loadClass(name);
}
return clazz;
}

public String toString()
{
return getClass().getName();
}
}

That works perfect when I have a normal client application but it
doesn't when I use Java Webstart.

Here my jnlp:

<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for SwingSet2 Demo Application -->
<jnlp
spec="1.0+"
codebase="http://localhost/jws6-bugreport"
href="Webstart6Bugreport.jnlp">
<information>
<title>Webstart 6 Bugreport</title>
<vendor>Skillworks AG</vendor>
<description>None</description>
<description kind="short">None</description>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.5"/>
<nativelib href="jws6-bugreport-native.jar"/>

<jar href="jws6-bugreport-app-1.0.jar" main="true"/>
<jar href="jws6-bugreport-jni-1.0.jar"/>

</resources>
<application-desc main-class="bugreport.jws6.ApplicationStarter"/>
</jnlp>


Here the native code:

public class NativeInterface {

public native String doSomething();
}


#include "NativeInterface.h"

JNIEXPORT jstring JNICALL
Java_bugreport_jws6_NativeInterface_doSomething
(JNIEnv *jEnv, jobject obj)
{

jstring referenceKey = jEnv->NewStringUTF("Native Call done");
return referenceKey;
}




/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class bugreport_jws6_NativeInterface */

#ifndef _Included_bugreport_jws6_NativeInterface
#define _Included_bugreport_jws6_NativeInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: bugreport_jws6_NativeInterface
* Method: doSomething
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_bugreport_jws6_NativeInterface_doSomething
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

Does anybody help me with that problem...?
Thanks for every hint
 
A

Andi

Here the Exception I got:

java.lang.UnsatisfiedLinkError: no jws6-bugreport in java.library.path
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at bugreport.jws6.Application.startup(Application.java:24)
at bugreport.jws6.Application.main(Application.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at bugreport.jws6.ApplicationStarter.main(ApplicationStarter.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.continueLaunch(Unknown Source)
at com.sun.javaws.Launcher.handleApplicationDesc(Unknown Source)
at com.sun.javaws.Launcher.handleLaunchFile(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
 
A

Andrew Thompson

I have a big problem to get my Application running on java webstart. I
have a custom classloader which will be used for some classes.

JWS *has* been known to be finicky with classloaders,
a lot of apps. used code that could 'discover' the
exact location to which it was downloaded. Changes
between 1.5 and 6.0 made that code break.

I am curious though to know exactly - *why*
are you using a custom classloader?
..Also I
need to load a dll which will be used by a native interface.

More on that below. *

(big snip...)
That works perfect when I have a normal client application but it
doesn't when I use Java Webstart.

Here my jnlp:

<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for SwingSet2 Demo Application -->

This is a fib, by the way. This is not
the SwingSet2 application. If we are going
to include comments, it seems sensible to
make them factual. ( And yes, I've been
caught out by the same thing myself ;)
<jnlp
  spec="1.0+"
  codebase="http://localhost/jws6-bugreport"
  href="Webstart6Bugreport.jnlp">
  <information>
    <title>Webstart 6 Bugreport</title>
    <vendor>Skillworks AG</vendor>
    <description>None</description>
    <description kind="short">None</description>
    <offline-allowed/>
  </information>
  <security>
      <all-permissions/>
  </security>
  <resources>
    <j2se version="1.5"/>
    <nativelib href="jws6-bugreport-native.jar"/>

<jar href="jws6-bugreport-app-1.0.jar" main="true"/>
<jar href="jws6-bugreport-jni-1.0.jar"/>

* OK. I think the nativelib element should be
*after* the jar elements. That is how it is
listed in the JNLP File Syntax here..
<http://java.sun.com/j2se/1.4.2/docs/guide/jws/developersguide/
syntax.html#resources>

JWS has also been known to be very finicky
about JNLP files, though frustratingly, it
makes a poor attempt at parsing invalid files,
and if it reports an error at all, it is usually
pointing to an entirely different element..

So, that brings me to the question..
Have you validated this JNLP file?

You might try validating it against the 1.5 DTD

Does anybody help me with that problem...?
Thanks for every hint

BTW - that was a great example you posted,
I would like to have tried it locally, but
unfortunately I do not have the immediate
means to generate the binary.

And another thing. The JNLP mentions 'bugreport'
in a number of parts. Have you actually lodged
a bug with Sun against this? Have you searched
the Bug DB for other related reports?
 
A

Andi

Hi,

I am using a custom classloader because some classes are encrypted. So
I have to decrypt them before.

I have validated the jnlp and it seems to be OK. When I start the
application without my custom classloader it is working perfect.

It is now my second time I added this issue to the sun bug database.
The first time I got an answer that there seems to be a problem but
they need
the source code or a test case to reconstruct it. But I have send it
to them everytime. I think the problem is that it needs a bit time to
deploy this example to reconstruct it.
So I thougt I ask the community in this forum. I could send you my
project. It should be buildable with maven and Visual Studio 2003 or
2005.

Thanks for the answer.
 
A

Andi

you might have a look how I handled this problem:

seehttp://mindprod.com/products1.html#SETCLOCK
--
Can You give me a hint where I should look in your sorce code?
Thanks
 
A

Andi

The source code is not likely the problem.

check:

1. the jnlp file.
2. how the dll fits in the jar and how it is named.
3. the load/loadlibrary

seehttp://mindprod.com/jgloss/jni.html

the native code class is called PCClock.

Yes, but that is working fine. When I don't use my custom classloader
everything is working. It is just a problem when I define a class
by myself (see CustomClassLoader / clazz = defineClass(name, buffer,
0, buffer.length); ). Now I have tested that I load all classes with
my custom classloader except the native interface and the class which
calls System.loadLibrary(...). So these classes will be loaded by the
parent classloader, the JNLPClassLoader. Then it is working. It is a
workaround but it didn't solve the problem.
 
R

Roedy Green

I have a big problem to get my Application running on java webstart. I
have a custom classloader which will be used for some classes. Also I
need to load a dll which will be used by a native interface.

I would suggest first writing a simplified test harness that exercises
the native method, without the complication of the custom class
loader.

Have a look at http://mindprod.com/projects1.html#SETCLOCK for a model
of how to use a native class in Java Web Start. Things to check:

1. name of dll in jar
2. name of dll in jnlp file
3. name of dll in loadlibrary

Make sure you are using the same patterns as I am.

Then be aware that the loadlibrary you do in custom loader X will be
visible only to classes loaded with that loader or its children.
 
R

Roedy Green

I have a big problem to get my Application running on java webstart. I
have a custom classloader which will be used for some classes. Also I
need to load a dll which will be used by a native interface.

You might also want to write a test harness for your native class that
does not use Java Web Start. Check out the tips at
http://mindprod.com/jgloss/jni.html
 
R

Roedy Green

Yes, but that is working fine. When I don't use my custom classloader
everything is working.

Very good. You have eliminated 75% of what could be going off the
rails.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top