OSGi容器中的RMI客户端

时间:2009-09-30 07:02:17

标签: java osgi rmi

我需要在OSGi包中公开一个基于RMI的系统。 RMI客户端“bundle”是一个jar,我使用bnd工具将其转换为OSGi包(我无法访问源代码),至少在eclipse中一切似乎都很好,但是当我尝试连接到RMI服务器抛出了ClassCastException,很可能是因为OSGi和RMI都很有趣地使用了ClassLoader。

我该如何解决这个问题?也许使用RMI客户端jar作为“系统”包?

这是堆栈跟踪:

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

2 个答案:

答案 0 :(得分:5)

由于类可见性问题,标准Java序列化和OSGi混合不好,并且RMI建立在序列化之上......

如果你四处寻找,你会发现很多人都在询问有关RMI和OSGi的信息,但对于具体的解决方案却很少。

我没有坐下来调查RMI和OSGi的特殊问题,但我确实解决了使用Spring HTTPInvoker的问题,它仍然使用Java的序列化机制。

问题归结为单个班级:ObjectInputStream

这是负责反序列化的人 - 并且要反序列化对象,您需要可以看到它的类。如果你有一个现代IDE,你可以查看这个类的继承层次结构,看看它有很多扩展,包括一些特定于RMI的类。

我的解决方案是使用Spring的ObjectInputStream的可扩展实现并从我的bundle中插入类加载器,这样反序列化就可以访问可以看到我的类的类加载器。

你可以使用系统捆绑包,但这真的是一个黑客,我不建议它长期使用。

不幸的是,OSGi仍然有一些令人讨厌的角落,需要你深入挖掘抽象层次才能找到问题并修复它--RMI就是其中之一。

Paremus人声称他们的服务架构服务器产品(一个基于OSGi的服务器)的RMI解决方案,并且可以配置为与Felix一起使用(我认为Eclipse的Equinox是默认设置)。 / p>

答案 1 :(得分:0)

我遇到了同样的问题,我很惊讶它是如何轻易解决的。我有三个捆绑包:bundleA,bundleB,bundleC。 bundleA - 一组对bundleB和bundleC一无所知的抽象类。 BundleB使用bundleA和bundleC。 bundleB由bundleB使用。

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

在bundleA中,我有代码调用RMI服务器并使用bundleC中的类。在这里我遇到了一个问题 - ClassNotFoundException。那么,我在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);
}