简体   繁体   English

OSGi容器中的RMI客户端

[英]RMI client in a OSGi container

I need to expose a RMI-based system in an OSGi bundle. 我需要在OSGi包中公开一个基于RMI的系统。 The RMI client "bundle" is a jar which I converted into a OSGi bundle using the bnd tool (I don't have access to the sources) and at least in eclipse everything seems to be fine, but when I try to connect to the RMI server, a ClassCastException is throwed, much probably because either OSGi and RMI make a funny use of the ClassLoader. RMI客户端“bundle”是一个jar,我使用bnd工具将其转换为OSGi包(我无法访问源代码),至少在eclipse中一切似乎都很好,但是当我尝试连接到RMI服务器抛出了ClassCastException,很可能是因为OSGi和RMI都很有趣地使用了ClassLoader。

How can I solve this? 我怎么解决这个问题? maybe using the RMI client jar as a "system" bundle? 也许使用RMI客户端jar作为“系统”包?

Here is the stack trace: 这是堆栈跟踪:

Blipnet OSGi service starting...
com.blipsystems.blipnet.api.blipserver.BlipServerConnectionException: There was a problem connecting to the server
    at com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(Unknown Source)
    at com.blipsystems.blipnet.api.core.blipserver.BlipServerConnectionAdapter.(Unknown Source)
    at com.blipsystems.blipnet.api.blipserver.BlipServer.getConnection(Unknown Source)
    at dk.itu.jingling.blipnetosgi.BlipnetConnectionService.setup(BlipnetConnectionService.java:28)
    at dk.itu.jingling.blipnetosgi.BlipnetConnectionService.(BlipnetConnectionService.java:22)
    at dk.itu.jingling.blipnetosgi.Activator.start(Activator.java:32)
    at org.apache.felix.framework.util.SecureAction$Actions.run(SecureAction.java:1235)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:658)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:1699)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:1621)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:890)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:877)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:819)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.start(DirectoryWatcher.java:805)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:798)
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:299)
Caused by: java.lang.ClassCastException: com.blipsystems.blipnet.blipserver.cms.NewApiHandler_Stub cannot be cast to com.blipsystems.blipnet.api.core.blipserver.RemoteBlipServerConnection

Standard Java serialization and OSGi don't mix well due to class visibility issues, and as RMI is built on top of serialization... 由于类可见性问题,标准Java序列化和OSGi混合不好,并且RMI建立在序列化之上......

If you google around, you'll find plenty of people asking about RMI and OSGi but little in the way of concrete solutions. 如果你四处寻找,你会发现很多人都在询问有关RMI和OSGi的信息,但很少有人会提出具体的解决方案。

I haven't sat down to investigate the particular problems of RMI and OSGi, but I did solve the problem of using Spring's HTTPInvoker , which still uses Java's serialization mechanism. 我没有坐下来调查RMI和OSGi的特殊问题,但我确实解决了使用Spring的HTTPInvoker的问题,它仍然使用Java的序列化机制。

The problem comes down to a single class: ObjectInputStream 问题归结为一个类: ObjectInputStream

This is the guy responsible for de-serializing - and to de-serialize an object you need visibility of its class. 这是负责反序列化的人 - 并且要反序列化对象,您需要可以看到它的类。 If you have an modern IDE you can look at the inheritance hierarchy of this class and see that there are many extensions of it, including a couple of classes specific to RMI. 如果你有一个现代IDE,你可以查看这个类的继承层次结构,看看它有很多扩展,包括一些特定于RMI的类。

My solution was to use Spring's extensible implementation of ObjectInputStream and plug in the classloader from my bundle, so that way the de-serialization would have access to a classloader that could see my classes. 我的解决方案是使用Spring的ObjectInputStream的可扩展实现并从我的bundle中插入类加载器,这样反序列化就可以访问可以看到我的类的类加载器。

You could play around with the system bundles, but that's really a hack and I wouldn't recommend it for long-term use. 你可以玩系统捆绑,但这真的是一个黑客,我不建议它长期使用。

Unfortunately, OSGi still has some nasty corners that require you to dig down in the levels of abstraction to find the problem and fix it - RMI is one of those. 不幸的是,OSGi仍然有一些令人讨厌的角落,需要你挖掘抽象层次来找到问题并修复它--RMI就是其中之一。

The Paremus guys claim to have a solution in their Service Fabric server product (an OSGi-based server) for RMI and that can be configured to work with Felix (I think Eclipse's Equinox is the default). Paremus的人声称他们的服务架构服务器产品(基于OSGi的服务器)的RMI有一个解决方案,并且可以配置为与Felix一起工作(我认为Eclipse的Equinox是默认的)。

I had the same problem and I am surprised how easily it is solved. 我有同样的问题,我很惊讶它是如何轻松解决的。 I have three bundles: bundleA, bundleB, bundleC. 我有三个捆绑包:bundleA,bundleB,bundleC。 bundleA - set of abstract classes which knows nothing about bundleB and bundleC. bundleA - 一组对bundleB和bundleC一无所知的抽象类。 BundleB uses bundleA and bundleC. BundleB使用bundleA和bundleC。 bundleC is used by bundleB. bundleB由bundleB使用。

So, bundleA <-- bundleB --> bundleC . 所以, bundleA <-- bundleB --> bundleC

In bundleA I have code that calls RMI server and work with classes from bundleC. 在bundleA中,我有代码调用RMI服务器并使用bundleC中的类。 And here I had a problem - ClassNotFoundException. 在这里我遇到了一个问题 - ClassNotFoundException。 So, the following code I used in class of bundleA 所以,我在bundleA类中使用了以下代码

ClassLoader threadClassLoader= Thread.currentThread().getContextClassLoader();
try {
    Class bundleCSomeClass = someVariablePassedFromBundleB.getMyClass();
    Thread.currentThread().setContextClassLoader(bundleCSomeClass.getClassLoader());
    //here we are calling RMI service
} catch (RemoteException ex) {

}finally{
    Thread.currentThread().setContextClassLoader(threadClassLoader);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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