简体   繁体   English

EJB到JNI(C ++)的调用

[英]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: 我的经验:

  1. So extra precaution has to be exercised when working with JNI code with packaged structure. 因此,在使用具有打包结构的JNI代码时,必须格外小心。
  2. java.library.path property is game changer in JNI java.library.path属性是JNI中的游戏规则改变者
  3. Eclispe java runtime and runtime of JNI has to be same Eclispe Java运行时和JNI运行时必须相同
  4. For C++, I noticed I had to place some additional system dependent libraries also in java.library.path apart from my native library. 对于C ++,我注意到除了本地库之外,我还必须在java.library.path中放置一些其他与系统相关的库。 They were used to link from MinGW compiler suite. 它们用于链接MinGW编译器套件。 They can be traced by running dependencyWalker. 可以通过运行dependencyWalker来跟踪它们。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM