[英]EJB to JNI (C++) call
I am trying to call a native library on windows (dll) from EJB using JNI. 我正在尝试使用JNI从EJB调用Windows(dll)上的本机库。 I have read lots of blogs and website suggests that making JNI calls from EJB is not allowed in EJB spec.
我读过很多博客和网站,建议EJB规范中不允许从EJB进行JNI调用。 There are vendor specific exceptions though.
但是,有特定于供应商的例外。 I am using weblogic as EJB container.
我正在使用weblogic作为EJB容器。 If you can guide/suggest me on this area.
如果您可以在这方面指导/建议我。 I know resource adapter is an option but it is an herculean task to implement for simple requirements.
我知道资源适配器是一个选项,但是对于简单的要求,它是一项艰巨的任务。 Here is my approach.
这是我的方法。
I developed a simple JNI which calls a C++ native library (also build by me) and prints the output: 我开发了一个简单的JNI,它调用了C ++本机库(也由我构建)并打印输出:
So JNI class HelloJNICpp calls the dll and invokes the a native method sayHello() , implemented in C++ , which gives the output 因此,JNI类HelloJNICpp调用dll并调用用C ++实现的本地方法sayHello() 。
Now, I implemented a session bean ( TestEJBBean.java ), a wrapper class HelloJNICpp.java (like JNI) which is called by the bean. 现在,我实现了一个会话bean( TestEJBBean.java ),这是一个由bean调用的包装类HelloJNICpp.java (如JNI)。 Finally a stand alone java client TestEJBClient.java to test the bean, whether it can be invoked and native could be called.
最后,一个独立的Java客户端TestEJBClient.java来测试bean,是否可以调用它以及是否可以调用native。
Here is the code details: 以下是代码详细信息:
Remote Interface 远端介面
package com.test.services;
import javax.ejb.Remote;
@Remote
public interface TestEJBRemote {
public void helloJNI();
}
Session Bean 会话Bean
package com.test.services;
import javax.ejb.Stateless;
@Stateless(mappedName = "TestEJB")
public class TestEJBBean implements TestEJBRemote {
public void helloJNI(){
new HelloJNICpp(). hello(); // Invoke native method
}
}
Wrapper class serves as JNI 包装器类充当JNI
package com.test.services;
public class HelloJNICpp {
static {
//System.load("hellocpp"); // hello.dll (Windows) or libhello.so (Unixes)
try{
System.loadLibrary("hellocpp");
}catch( Exception e){
System.out.println("Some problem occurred while loading library.");
}
}
// Native method declaration
private native void sayHello();
// Test Driver
public static void hello() {
new HelloJNICpp().sayHello(); // Invoke native method
}
}
Bean test client Bean测试客户端
package com.test.client;
import com.test.services.*;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class TestEJBClient {
public static void main (String args[]){
try {
Context ctx = new InitialContext(getInitialContext());
TestEJBRemote testBean = (TestEJBRemote) ctx.lookup("TestEJB#com.test.services.TestEJBRemote");
testBean.helloJNI();
} catch (NamingException e) {
e.printStackTrace();
}
}
private static Hashtable<String, Object> getInitialContext() {
Hashtable<String, Object> properties = new Hashtable<String, Object>();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
return properties;
}
}
I placed the dll library in all possible locations like java library path can include like C:\\Windows\\System32 , weblogic domain lib, even I bundled that with EJB application and deployed it. 我将dll库放在所有可能的位置,例如java库路径可以包括C:\\ Windows \\ System32 ,weblogic域lib,甚至我将其与EJB应用程序捆绑并部署了它。 When I execute the client I get UnsatisfiedLink Error.
执行客户端时,出现UnsatisfiedLink错误。
Exception in thread "main" javax.ejb.EJBException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V; nested exception is: java.rmi.RemoteException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
java.rmi.RemoteException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:237)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:259)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl_1036_WLStub.helloJNI(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:85)
at $Proxy0.helloJNI(Unknown Source)
at com.test.client.TestEJBClient.main(TestEJBClient.java:14)
Caused by: java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
at com.test.services.HelloJNICpp.sayHello(Native Method)
at com.test.services.HelloJNICpp.hello(HelloJNICpp.java:19)
at com.test.services.TestEJBBean.helloJNI(TestEJBBean.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.bea.core.repackaged.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.oracle.pitchfork.spi.MethodInvocationVisitorImpl.visit(MethodInvocationVisitorImpl.java:34)
at weblogic.ejb.container.injection.EnvironmentInterceptorCallbackImpl.callback(EnvironmentInterceptorCallbackImpl.java:54)
at com.oracle.pitchfork.spi.EnvironmentInterceptor.invoke(EnvironmentInterceptor.java:42)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy200.helloJNI(Unknown Source)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl.__WL_invoke(Unknown Source)
at weblogic.ejb.container.internal.SessionRemoteMethodInvoker.invoke(SessionRemoteMethodInvoker.java:40)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl.helloJNI(Unknown Source)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl_WLSkel.invoke(Unknown Source)
at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:667)
at weblogic.rmi.cluster.ClusterableServerRef.invoke(ClusterableServerRef.java:230)
at weblogic.rmi.internal.BasicServerRef$1.run(BasicServerRef.java:522)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
at weblogic.rmi.internal.BasicServerRef.handleRequest(BasicServerRef.java:518)
at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
Here is the project structure: 这是项目结构:
Is it technically not possible to call/load a native library from EJB or am I missing something? 从技术上讲不可能从EJB调用/加载本机库还是我遗漏了什么? I am sure thar static block is not throwing any exception because, it has a try-catch block and no exception is caught in weblogic level.
我可以肯定,该静态块不会引发任何异常,因为它具有try-catch块,并且在weblogic级别中未捕获任何异常。
Thanks in advance. 提前致谢。
I investigated from all corners, keeping all the aspects in mind and finally able to resolve the issue. 我从各个角度进行了调查,牢记所有方面,终于能够解决问题。 I understood technically it is possible to call a JNI library from a session bean (deployed on Weblogic), however it may not be a suggested practice from a EJB spec point of view because the native library call makes the bean system dependent and it is no more portable.
我从技术上理解可以从会话bean(在Weblogic上部署)中调用JNI库,但是从EJB规范的角度来看这可能不是建议的做法,因为本机库调用使bean系统依赖于它,更便携。
As UnsatisfiedLinkError has various natures, the following 由于UnsatisfiedLinkError具有多种性质,因此以下内容
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
looks like at runtime JNI binding is failing. 看起来在运行时JNI绑定失败。 Approaches I took to resolve the issue:
我采取的解决方法:
Checking java.library.path - 检查java.library.path-
As friends suggested, I wrote 正如朋友建议的那样,我写道
System.getProperty("java.library.path")
inside the bean and make sure my dll was already there. 在bean中,并确保我的dll已经存在。 For my case it was OS library load path C:/Windows/System32 (eventhough I had this library also in my local practice folder where from I was executing the JNI)
就我而言,它是OS库的加载路径C:/ Windows / System32 (尽管我在我执行JNI的本地练习文件夹中也有此库)
Checking the folder permission The folder containing the native library was also there with read-write-execute permission 检查文件夹权限包含本地库的文件夹也在那里,具有读写执行权限
Container library path 容器库路径
I placed the library in [WEBLOGIC_HOME]/server/lib so that at runtime container picks up. 我将库放在[WEBLOGIC_HOME] / server / lib中,以便在运行时收集容器。 Even this was not resolving the issue
即使这样也无法解决问题
JNI signature I thought of revisiting my JNI header files and native implementations. JNI签名我考虑过重新访问JNI头文件和本机实现。 I discovered the when I created the header file (HelloJNICpp.h) the source JAVA class did not contain the package statement.
我在创建头文件(HelloJNICpp.h)时发现源JAVA类不包含package语句。 I included the package statement later to run it from Eclipse.
稍后,我包含了package语句以从Eclipse运行它。 This was a problem is my code it self.
这是一个问题,这是我自己编写的代码。 So initially it was:
因此最初是:
JNIEXPORT void JNICALL Java_HelloJNICpp_sayHello (JNIEnv *env, jobject thisObj)
later after creating with proper package structure: 使用适当的包结构创建之后:
JNIEXPORT void JNICALL Java_com_test_services_HelloJNICpp_sayHello (JNIEnv *env, jobject thisObj)
and this worked! 这有效! My learnings:
我的经验:
An EJB should call native code via a JCA Resource Adapter. EJB应该通过JCA资源适配器调用本机代码。
A sample is in JNI-RA-HOWTO : https://wiki.ow2.org/jonas/Wiki.jsp?page=JNIRAHOWTO JNI-RA-HOWTO中有一个示例: https : //wiki.ow2.org/jonas/Wiki.jsp? page =JNIRAHOWTO
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.