How to use kyotocabinet(JNI) in playframework? - java

I'm tackling to use kyotocabinet in Playframework.
and following error occurred.
I'm using Eclipse and playframework-1.2.3.
and kyotocabinet is native library so I'm using its Java-Binding.
the reproduce code is simple.
in controller:
public static void somePage() {
DB db = new DB();//error occurred
render();
}
Internal Server Error (500) for request GET /
Execution exception (In /app/controllers/TestApp.java around line 45)
NoClassDefFoundError occured : Could not initialize class kyotocabinet.DB
play.exceptions.JavaExecutionException: Could not initialize class kyotocabinet.DB
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:229)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class kyotocabinet.DB
at controllers.TestApp.somePage(TestApp.java:45)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:546)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:500)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:476)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:471)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:159)
... 1 more
build in Eclipse was completed but error occured at runtime.
I guess it is because kyotocabinet.dll is missing.(only jkyotocabinet.jar was found)
I configured the location of kyotocabinet.dll to Java Build Path > Source > Native Library Location of my playframework project.
and it was good in other projects.
How to use native library in playframework?
any example or tutorial?
Play.getFile and System.load didn't work.
package controllers;
import play.Play;
import play.jobs.*;
#OnApplicationStart
public class Bootstrap extends Job {
public void doJob() {
String path = "D:/MyProject/lib/jkyotocabinet.dll";
Play.getFile(path);
//System.load(path); if this was enabled, following error occurred: "Native Library D:\MyProject\lib\jkyotocabinet.dll already loaded in another classloader". so I guess the dll was loaded.
System.out.println("bootstrap loaded");//this is displayed.
}
}
UnsatisfiedLinkError occured : no jkyotocabinet in java.library.path
this Japanese blog tells Play!Framework cannot load native library.
http://d.hatena.ne.jp/hjym_u/20110702/1309609277
I already tried these: Absolute path, Relative path, System.load, System.loadLibrary, Play.getFile.
as conclusive approach, I put jkyotocabinet.dll to current directory(D:/MyProejct/), and wrote this code.
public static void somePage(){
File f = Play.getFile("jkyotocabinet.dll");
if(f != null && f.isFile() && f.canRead() && f.canExecute()){//true
DB db = new DB();//error occured. it reached here.
}
render();
}
Execution exception
NoClassDefFoundError occured : Could not initialize class kyotocabinet.DB
Play.getFile found the path "jkyotocabinet.dll" so jkyotocabinet.dll is in current directory so jvm should find it automatically.
anyone can use JNI in playframework?
finally, I could use kyotocabinet as PROD mode but not DEV mode.
Project/conf/application.conf
#application.mode=dev
application.mode=prod

I assume you just need to load the dll into Java via System.load
If you place the ddl on your project, you may load it via Play.getFile inside your #OnApplicationStart controller. This should make it available to your application while the JVM is alive.
EDIT:
#KenichiYamamoto Play.getFile gets files from the application path. You are trying to use a full path in there.
Read this about loading the file in a container. It may be that (due to Play compile-reload system) you are hitting the "already loaded" error. Try to follow the example by adding the System.load inside a static block in your #OnApplicationStart

Do as pere says but use the relative path from your application root. Not the absolute path. I.e. Play.getFile("lib\myfile.dll")

Related

Compiling JD2XX for Raspberry Pi

For Openhab2 there is a binding add-on called RFXCOM. The problem however is that this add-on uses JD2XX which is not compatible with the ARM architecture of the Raspberry Pi.
I have found a Github repository with the source that you can use to compile a *.so file: https://github.com/0x6a77/JD2XX
A little change to the Makefile to use the correct Java path (zulu-8-armhf-embedded instead of (oracle-7).
Running sudo make jni creates a *.so file which I copied to /usr/lib (inside the java library path). However I still get the error that the Raspberry Pi can't open the shared library due to it being 32-bit. How can you compile a shared library that works for ARM with the source provided by the Github repository.
Error message:
java.lang.UnsatisfiedLinkError:
/var/lib/openhab2/tmp/libjd2xx5892592723514582617.so:
/var/lib/openhab2/tmp/libjd2xx5892592723514582617.so: cannot open shared object file:
No such file or directory (Possible cause: can't load IA 32-bit .so on a ARM-bit platform)
The Raspberry Pi has a fresh installation of Openhabian.
Link to the issue on Github: https://github.com/openhab/openhab2-addons/issues/2316#issuecomment-304795652
EDIT:
11:00:52.291 [ERROR] [rnal.discovery.RFXComBridgeDiscovery] - Error occurred during discovery
java.io.IOException: device not found (2)
at jd2xx.JD2XX.listDevices(Native Method)
at jd2xx.JD2XX.listDevicesByDescription(JD2XX.java:785)
at org.openhab.binding.rfxcom.internal.discovery.RFXComBridgeDiscovery.discoverRfxcom(RFXComBridgeDiscovery.java:89)
at org.openhab.binding.rfxcom.internal.discovery.RFXComBridgeDiscovery.startScan(RFXComBridgeDiscovery.java:66)
at org.eclipse.smarthome.config.discovery.AbstractDiscoveryService.startScan(AbstractDiscoveryService.java:199)
at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:382)
at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScans(DiscoveryServiceRegistryImpl.java:358)
at org.eclipse.smarthome.config.discovery.internal.DiscoveryServiceRegistryImpl.startScan(DiscoveryServiceRegistryImpl.java:216)
at org.eclipse.smarthome.io.rest.core.discovery.DiscoveryResource.scan(DiscoveryResource.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)[:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498)[:1.8.0_121]
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)[157:org.glassfish.jersey.core.jersey-common:2.22.2]
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)[158:org.glassfish.jersey.core.jersey-server:2.22.2]
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)[155:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)[155:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)[155:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)[155:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)[155:org.glassfish.jersey.containers.jersey-container-servlet-core:2.22.2]
at com.eclipsesource.jaxrs.publisher.internal.ServletContainerBridge.service(ServletContainerBridge.java:76)[10:com.eclipsesource.jaxrs.publisher:5.3.1.201602281253]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)[81:org.eclipse.jetty.servlet:9.2.19.v20160908]
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:587)[81:org.eclipse.jetty.servlet:9.2.19.v20160908]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71)[172:org.ops4j.pax.web.pax-web-jetty:4.3.0]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)[79:org.eclipse.jetty.security:9.2.19.v20160908]
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:287)[172:org.ops4j.pax.web.pax-web-jetty:4.3.0]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)[81:org.eclipse.jetty.servlet:9.2.19.v20160908]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80)[172:org.ops4j.pax.web.pax-web-jetty:4.3.0]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.Server.handle(Server.java:499)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)[80:org.eclipse.jetty.server:9.2.19.v20160908]
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)[72:org.eclipse.jetty.io:9.2.19.v20160908]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)[83:org.eclipse.jetty.util:9.2.19.v20160908]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)[83:org.eclipse.jetty.util:9.2.19.v20160908]
at java.lang.Thread.run(Thread.java:745)[:1.8.0_121]
11:01:02.868 [WARN ] [e.sshd.server.channel.ChannelSession] - Unknown pty opcode value: 42
In the JD2XX.java file, you can see the mechanism how to load a dll, so or some other type of library depending on OS.
static {
String dataModel = System.getProperty("sun.arch.data.model");
String osName = System.getProperty("os.name").toLowerCase();;
StringBuilder lib = new StringBuilder("/jni/");
if (osName.contains("win"))
lib.append("win/");
else if (osName.contains("linux"))
lib.append("linux/");
else if (osName.contains("mac"))
lib.append("mac/");
else
throw new UnsatisfiedLinkError("Loading JD2XX JNI: Unsupported operating system ("+osName+")");
if (dataModel.equals("32"))
lib.append("x86_32/");
else if (dataModel.equals("64"))
lib.append("x86_64/");
else
throw new UnsatisfiedLinkError("Loading JD2XX JNI: Unknown runtime data model ("+dataModel+")");
if (osName.contains("win"))
lib.append("jd2xx.dll");
else if (osName.contains("linux"))
lib.append("libjd2xx.so");
else if (osName.contains("mac"))
lib.append("libjd2xx.jnilib");
try {
NativeUtils.loadLibraryFromJar(lib.toString());
} catch (IOException e) {
throw new UnsatisfiedLinkError(e.getMessage());
}
}
The loadLibraryFromJar method from NativeUtils creates temp directory and copy the right library for OS to temp directory then call the System.load method eventually.
So, I think you should modify this part of source code like the code as follows, if possible.
static
{
System.load("/var/lib/openhab2/tmp/libjd2xx5892592723514582617.so");
}
or
static
{
System.load("/usr/lib/libjd2xx5892592723514582617.so");
}
There are several ways to make this job work re-setting the 'java.library.path' order to indicate the /usr/lib directory first then use the code below.
Or you can rename the library name, libjd2xx5892592723514582617.so to libjd2xx.so in the /usr/lib which is usually in the 'LD_LIBRARY_PATH' variable.
then, our code in the JD2XX.java can be used instead,
static
{
System.loadLibrary("jd2xx");
}
I think it works..

SWI-Prolog: Could not open resource database "../../src/swipl.prc"

I have checked out the SWI-Prolog JPL library, and I am trying to add some functionality. Right now, I am just trying to get the tests to work in the TestJUnit test. However, I am getting the following error:
SWI-Prolog: [FATAL ERROR:
Could not open resource database "../../src/swipl.prc": No error]
I have looked at the code, and I know that path is coming from this declaration:
public static final String startup =
(System.getenv("SWIPL_BOOT_FILE") == null ? "../../src/swipl.prc" :
System.getenv("SWIPL_BOOT_FILE"));
It is looking for a an environment variable %SWIPL_BOOT_FILE%, so I could see how this might fix the problem. However, I don't know which file I should add as the boot file.
I have tried the swipl-win.exe, but that doesn't work.
Any ideas?

java.lang.NoSuchMethodError exception for having correct JAR loaded

I am writing a Java web app and put in Tomcat to run.
When I tried to use a method included in JAR (which I am sure it contains the method I need), it shows:
java.lang.NoSuchMethodError: com.couchbase.client.CouchbaseClient.asyncGetBulk(Ljava/util/Collection;)Ljava
But I tried to started tomcat by -verbose:class, I see the following log:
[Loaded net.spy.memcached.ops.VBucketAware from file:/.../apache-tomcat-5.5.30/webapps/.../WEB-INF/lib/spymemcached-2.8.2.jar]
[Loaded net.spy.memcached.protocol.binary.SingleKeyOperationImpl from file:/.../apache-tomcat-5.5.30/webapps/.../WEB-INF/lib/spymemcached-2.8.2.jar]
[Loaded net.spy.memcached.protocol.binary.GetOperationImpl from file:/.../apache-tomcat-5.5.30/webapps/.../WEB-INF/lib/spymemcached-2.8.2.jar]
Exception in thread "Thread-2139" java.lang.NoSuchMethodError: com.couchbase.client.CouchbaseClient.asyncGetBulk(Ljava/util/Collection;)Ljava/util/concurrent/Future
While spymemcached-2.8.2.jar contains the method, so I do not understand why it fails.
This is how I call the method:
Future<Map<String,Object>> f = client.asyncGetBulk(key);
Thanks for your help.
Update 1:
By using the code #Narendra Pathai provides, I got the following result
[
file:/.../WEB-INF/classes/,
file:/.../WEB-INF/lib/activation-1.1.jar,
file:/.../WEB-INF/lib/commons-codec-1.5.jar,
file:/.../WEB-INF/lib/commons-lang-2.2.jar,
file:/.../WEB-INF/lib/commons-logging-1.1.1.jar,
file:/.../WEB-INF/lib/couchbase-client-1.0.3.jar,
file:/.../WEB-INF/lib/jaxb-api-2.1.jar,
file:/.../WEB-INF/lib/jaxb-impl-2.1.9.jar,
file:/.../WEB-INF/lib/jettison-1.1.jar,
file:/.../WEB-INF/lib/netty-3.2.0.Final.jar,
file:/.../WEB-INF/lib/runtime-0.4.1.5.jar,
file:/.../WEB-INF/lib/spymemcached-2.8.2.jar,
file:/.../WEB-INF/lib/stax-api-1.0-2.jar,
file:/.../WEB-INF/lib/xxx_core.jar,
file:/.../WEB-INF/lib/xxx_couchbase.jar
]
They do not contain the file with the path com.couchbase.client.CouchbaseClient.asyncGetBulk
except couchbase-client-1.0.3.jar.
Update 2:
By using the code:
CodeSource codeSource = CouchbaseClient.class.getProtectionDomain().getCodeSource();
if (codeSource != null) {
log.debug(codeSource.getLocation());
}
CodeSource codeSource2 = net.spy.memcached.MemcachedClient.class.getProtectionDomain().getCodeSource();
if (codeSource2 != null) {
log.debug(codeSource2.getLocation());
}
I have got the following result:
file:/.../WEB-INF/lib/couchbase-client-1.0.3.jar
file:/.../WEB-INF/lib/spymemcached-2.8.2.jar
It seems that they are correct too.
Problem is of classpath
public static void main(String[] args) {
URLClassLoader classLoader = (URLClassLoader)Main.class.getClassLoader();
System.out.println(Arrays.toString(classLoader.getURLs()));
}
Use this method in your Main class to find out from where all the jar dependencies are resolved.
See if older version of the jar is being loaded by the classloader
I had similar issue, but with one of my own libraries, but thanks to this code submitted by #Narendra Pathai
URLClassLoader classLoader = (URLClassLoader)Main.class.getClassLoader();
System.out.println(Arrays.toString(classLoader.getURLs()));
I found that classpath was using some very old version of my library.
Then I clean up the build folder (because I'm using gradle) and everything compiled and run ok.
Probably, there is a class with the same canonical name, which is located upper in the classpath.
JVM picks the first class and does not find the needed method. Check if you have multiple versions of the same library in your classpath
Have you tried to put the Couchbase dependencies in $TOMCAT_HOME/lib just for testing first.
And removing them from your WAR
If you run your jar with java -Dloader.path='dependency_jar_dir', and there are more than one jar with different versions[such as :com.a.1.1.jar,com.a.1.2.jar], it will be wrong!

Why do I get NoClassDefFoundError: java/awt/Desktop?

I'm trying to open an URI with Swing that I get above error.
What is the reason and how can I fix it?
When I do it in console everything is OK but when I do in GUI I get this error.
I should say that I use Weblogic as server.
Code
private static void open(URI uri) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(uri);
} catch (IOException e) { /* TODO: error handling */ }
} else { /* TODO: error handling */ }
}
Stack trace:
Exception in thread "AWT-EventQueue-1" java.lang.NoClassDefFoundError: java/awt/Desktop
at be.azvub.ext.bcfidownloder.BcfiDownloadPanel.open(BcfiDownloadPanel.java:230)
at be.azvub.ext.bcfidownloder.BcfiDownloadPanel.access$000(BcfiDownloadPanel.java:37)
at be.azvub.ext.bcfidownloder.BcfiDownloadPanel$7.actionPerformed(BcfiDownloadPanel.java:147)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:5517)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3129)
at java.awt.Component.processEvent(Component.java:5282)
at java.awt.Container.processEvent(Container.java:1966)
at java.awt.Component.dispatchEventImpl(Component.java:3984)
at java.awt.Container.dispatchEventImpl(Container.java:2024)
at java.awt.Component.dispatchEvent(Component.java:3819)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3892)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
at java.awt.Container.dispatchEventImpl(Container.java:2010)
at java.awt.Window.dispatchEventImpl(Window.java:1791)
Doc on NoClassDefFoundError
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.
You do have some incorrect classloading happening. Mostly due to wrong class loader chaining.
NoClassDefFoundError can only be caused by a classpath problem.
Because Desktop is part of jre, make sure that your classpath contains a reference to the jre library.
In Eclipse, you can go to run configurations --> Classpath and check there
UPDATE:
As Andrew suggested, you can also check you have at least java 1.6
java.awt.Desktop has been introduced in Java 6. Chances are high you're running your code on different JRE versions.

Working with libpath with java reflection

I'm dynamically loading a class and calling a method on it. This class does JNI. When I call the class, java attempts to load the library. This causes an error because the library is not on the libpath. I'm calling from instead a jar so I can't easily change the libpath (especially since the library is not in the same directory or a sub directory of the jar). I do know the path of the library, but how can I load it before I load the class.
Current code:
public Class<?> loadClass(String name) throws ClassNotFoundException {
if(!CLASS_NAME.equals(name))
return super.loadClass(name);
try {
URL myUrl = new URL(classFileUrl);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
byte[] classData = readConnectionToArray(input);
return defineClass(CLASS_NAME,
classData, 0, classData.length);
} catch (MalformedURLException e) {
throw new UndeclaredThrowableException(e);
} catch (IOException e) {
throw new UndeclaredThrowableException(e);
}
}
Exception:
Can't find library libvcommon.so
java.lang.UnsatisfiedLinkError: vcommon (A file or directory in the path name does not exist.)
at java.lang.ClassLoader.loadLibraryWithPath(ClassLoader.java:998)
at java.lang.ClassLoader.loadLibraryWithClassLoader(ClassLoader.java:962)
at java.lang.System.loadLibrary(System.java:465)
at vcommon.(vcommon.java:103)
at java.lang.J9VMInternals.initializeImpl(Native Method)
at java.lang.J9VMInternals.initialize(J9VMInternals.java:200)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:599)
at com.fortune500.fin.v.vunit.reflection.ReflectionvProcessor.calculateV(ReflectionvProcessor.java:36)
at com.fortune500.fin.v.vunit.UTLTestCase.execute(UTLTestCase.java:42)
at com.fortune500.fin.v.vunit.TestSuite.execute(TestSuite.java:15)
at com.fortune500.fin.v.vunit.batch.Testvendor.execute(Testvendor.java:101)
at com.fortune500.fin.v.vunit.batch.Testvendor.main(Testvendor.java:58)
Edit: I'm having a 64bit vs 32bit issue right now. I'll come back to this when I've sorted that out.
Related: Dynamic loading a class in java with a different package name
If you know the path to the library, you could add the path to the java.library.path environment variable in your custom class loader. A simpler approach is to compute the path and use it in your call to Runtime.loadLibrary.
The code below outlines two approaches, using loadLibrary and setting the java.library.path system property.
if(CLASS_NAME.equals(name)) {
// two ways of doing this - either load the library explicitly from the full path
if (useFullPath) {
Runtime.getRuntime().loadLibrary("/full/path/to/mylibrary");
}
else { // or tweaking the library path
System.setProperty("java.library.path",
System.getProperty("java.library.path")
+ System.getProperty("file.separator")
+ "/path/to/lib");
}
}
return super.loadClass(name);
You mention your code is being called from a jar - using a custom class loader is going to be difficult if the ClassLoader is part of the jar as well. Have you verified that your class loader is indeed being used?
A simpler approach is to change the current call to loadLibrary in your native class to use the full path. E.g. fetch from system properties, or compute it, if you know in advance where to find it. This is only an option of course if you have the source to the native class. If you can't modify the native class, then use the loadLibrary call in the classloader.
It's my understanding that calls to load library with the same library name (regardless of path) load the same library. (At least, that's the behaviour on Windows - I haven't verified on Linux.) So, even though the classloader loads the library using the full path, and the native class loads the library using it's simple name, both should resolve to the same library.
(Just for completeness, resolving equivalent libraries happens in the kernel, again, speaking from Win32 experience. Each library internally has a name, and windows only loads one instance of the library with the same internal name per process.)

Categories

Resources