简体   繁体   English

带有Apache Karaf Cellar的分布式OSGi示例-客户端捆绑无法激活,因为找不到分布式服务

[英]Distributed OSGi example with Apache Karaf Cellar - Client bundle can't activate because can't find distributed service

I am using Apache Karaf 4.1.1 and Karaf Cellar. 我正在使用Apache Karaf 4.1.1和Karaf Cellar。 I have written two bundles. 我写了两捆。 The first bundle provides a service of type ITrackerManager. 第一个捆绑软件提供了ITrackerManager类型的服务。 The second bundle has a component that references ITrackerManager. 第二个捆绑软件具有引用ITrackerManager的组件。 My end goal is to witness the component in the second bundle successfully get a reference to the ITrackerManager service in the first bundle which is running on a different node. 我的最终目标是见证第二个捆绑软件中的组件成功获取对在不同节点上运行的第一个捆绑软件中ITrackerManager服务的引用。 This is all part of my exploration of distributed OSGi. 这是我探索分布式OSGi的全部内容。

What is actually happening when I install that second bundle is that it gets installed but fails to activate due to missing the service reference. 当我安装第二个捆绑软件时,实际上发生的是它已安装但由于缺少服务引用而无法激活。 I must be conducting my test incorrectly. 我必须进行错误的测试。 Any ideas on how I would go about demonstrating my end goal; 关于如何证明自己的最终目标的任何想法; component in bundle on Node B successfully uses service on Node A? 节点B上的捆绑中的组件成功使用节点A上的服务?


Here is how I have run my test so far. 到目前为止,这是我进行测试的方式。

Node A 节点A

karaf@root()> cluster:node-list
  | Id                | Alias | Host Name    | Port
--+-------------------+-------+--------------+-----
x | 159.4.251.58:5701 |       | 159.4.251.58 | 5701
  | 159.4.251.58:5702 |       | 159.4.251.58 | 5702

Node B 节点B

karaf@root()> cluster:node-list
  | Id                | Alias | Host Name    | Port
--+-------------------+-------+--------------+-----
  | 159.4.251.58:5701 |       | 159.4.251.58 | 5701
x | 159.4.251.58:5702 |       | 159.4.251.58 | 5702

So far so good. 到现在为止还挺好。 I am running two karaf instances on my computer. 我在计算机上运行两个karaf实例。 Both instances see each other. 两个实例都可以看到。 Now I want to install that first bundle onto Node A ONLY. 现在,我只想将第一个捆绑软件安装到节点A上。 To accomplish that, I install the bundle into the cluster, then specifically remove it from Node B. 为此,我将捆绑软件安装到群集中,然后从节点B中专门删除它。

Node A 节点A

karaf@root()> cluster:bundle-install -s default mvn:myCompany/dosgi-example-part1/1.0-SNAPSHOT

karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State    | Lvl | Located       | Blocked | Version        | Name
---+----------+-----+---------------+---------+----------------+--------------------------------------------------------------
 0 | Active   |     | cluster/local |         | 5.6.2          | System Bundle
...
67 | Active   |     | cluster/local       |         | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1

karaf@root()> cluster:service-list
Service Class             | Provider Node
--------------------------+------------------
myCompany.ITrackerManager | 159.4.251.58:5701
                          | 159.4.251.58:5702

Still looking good. 看起来还不错。 My bundle is in the cluster, is local on Node A (and Node B at this point), and the service is recognized by the cluster and is available on both Node A and Node B. Now to remove the bundle from Node B. 我的捆绑软件位于群集中,在节点A(此时为节点B)上是本地的,并且该服务可被群集识别,并且在节点A和节点B上均可用。现在从节点B中删除捆绑软件。

Node B 节点B

karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State    | Lvl | Located       | Blocked | Version        | Name
---+----------+-----+---------------+---------+----------------+-------------------------------------------------------------
67 | Active   |     | cluster/local |         | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1

karaf@root()> bundle:list
START LEVEL 100 , List Threshold: 50
ID | State  | Lvl | Version        | Name
---+--------+-----+----------------+-----------------------------------------------
75 | Active |  80 | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1

karaf@root()> bundle:uninstall 75

karaf@root()> cluster:bundle-list default
Bundles in cluster group default
ID | State    | Lvl | Located       | Blocked | Version        | Name
---+----------+-----+---------------+---------+----------------+--------------------------------------------------------------
67 | Active   |     | cluster |         | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 1

karaf@root()> cluster:service-list
Service Class             | Provider Node
--------------------------+------------------
myCompany.ITrackerManager | 159.4.251.58:5701

Excellent. 优秀的。 The first bundle has been removed from Node B but still shows up as being in the cluster. 第一个捆绑包已从节点B中删除,但仍显示为在群集中。 Both nodes agree that my service is only available on Node A now (since the bundle was removed from Node B). 两个节点都同意我的服务现在仅在节点A上可用(因为从节点B删除了捆绑包)。 Now I will load my second bundle on Node B only. 现在,我将仅在节点B上加载第二个捆绑包。 This is where I run into problems. 这是我遇到问题的地方。 I don't load the second bundle using the cluster:bundle-install command because I don't want it ending up on Node A. So instead I install my second bundle using the normal bundle:install command. 我不使用cluster:bundle-install命令加载第二个捆绑包,因为我不希望它最终出现在节点A上。因此,我使用普通的bundle:install命令安装了第二个捆绑包。 This results in an error about an unsatisfied reference. 这会导致有关参考文献不满意的错误。

Node B 节点B

karaf@root()> bundle:install -s mvn:otherCompany/dosgi-example-part2/1.0-SNAPSHOT
Bundle ID: 76
Error executing command: Error installing bundles:
        Unable to start bundle mvn:otherCompany/dosgi-example-part2/1.0-SNAPSHOT: org.osgi.framework.BundleException: Unable to resolve otherCompany.dosgi-example-part2 [76](R 76.0): missing requirement [otherCompany.dosgi-example-part2 [76](R 76.0)] osgi.wiring.package; (&(osgi.wiring.package=myCompany)(version>=1.0.0)(!(version>=2.0.0))) Unresolved requirements: [[otherCompany.dosgi-example-part2 [76](R 76.0)] osgi.wiring.package; (&(osgi.wiring.package=myCompany)(version>=1.0.0)(!(version>=2.0.0)))]

karaf@root()> bundle:list
START LEVEL 100 , List Threshold: 50
ID | State     | Lvl | Version        | Name
---+-----------+-----+----------------+-----------------------------------------------------------------------------------------------------
76 | Installed |  80 | 1.0.0.SNAPSHOT | Distributed OSGi Example Part 2

So there it is. 就是这样。 I install the second bundle on NodeB only, expecting that it is able to successfully use the required service which resides on Node A only. 我仅将第二个捆绑软件安装在NodeB上,希望它能够成功使用仅驻留在Node A上的必需服务。 Unfortunately that does not happen. 不幸的是,这不会发生。 Instead I get error message stating there are unresolved requirements. 相反,我收到错误消息,指出存在未解决的要求。 It seems to behave as if DOSGI is not available. 看起来好像DOSGI不可用。 If I install both bundles on the same node, the second bundle activates without any errors. 如果我将两个捆绑软件都安装在同一节点上,则第二个捆绑软件会激活,而不会出现任何错误。 Any insights you may have would be appreciated. 您的任何见解将不胜感激。

My problem was two-fold. 我的问题有两个。

  1. Stuff to be sent over DOSGI needs to be serializable. 通过DOSGI发送的东西需要可序列化。 In my case, I was calling a method on a remote service that took an argument. 就我而言,我正在远程服务上调用带有参数的方法。 That argument was a class type defined in a common API. 该参数是通用API中定义的类类型。 That class type was not serializable. 该类类型不可序列化。 Once I made it serializable, it starting getting different errors. 一旦使它可序列化,它就会开始出现不同的错误。 Which brings me to... 带我去...

  2. Normal name space rules apply. 普通名称空间规则适用。 I will elaborate below. 我将在下面详细说明。

My API defined two interfaces. 我的API定义了两个接口。

  • ITracker ITracker
  • ITrackerManager ITrackerManager

That API bundle was installed into the cluster so it is available on all nodes. 该API捆绑包已安装到集群中,因此在所有节点上都可用。 My Service bundle had a concrete implementation of ITrackerManager. 我的服务包具有ITrackerManager的具体实现。 When that bundle is installed locally on Node A, the cluster:service-list command correctly shows that Node A has a service of type ITrackerManager. 当该捆绑包本地安装在节点A上时,cluster:service-list命令正确显示节点A具有ITrackerManager类型的服务。

My Client bundle has a concrete implementation of ITracker that had a reference to ITrackerManager which was installed on Node B. The first thing the ITracker instance did in its activate method was call ITrackerManager.addTracker(this). 我的客户端捆绑软件具有ITracker的具体实现,该实现引用了已安装在节点B上的ITrackerManager。ITracker实例在其activate方法中所做的第一件事是调用ITrackerManager.addTracker(this)。 What should have happened was that the instance of ITracker on Node B provided itself to the ITrackerManager running on Node A. Initially this failed because ITracker was not serializable. 应该发生的是,节点B上的ITracker实例将自身提供给在节点A上运行的ITrackerManager。最初,此操作失败,因为ITracker无法序列化。 Once that was solved, I started seeing classNotFound exceptions on Node A. 解决之后,我开始在节点A上看到classNotFound异常。

Node A was trying to deserialize the ITracker instance locally. 节点A尝试在本地反序列化ITracker实例。 It was attempting to deserailize a concrete class (TheirTracker) which was not defined locally, it was only defined on Node B in the client bundle. 它试图对未本地定义的具体类(TheirTracker)进行反序列化,该类仅在客户端包中的节点B上定义。 This failed. 这失败了。

So the normal namespace rules apply. 因此,通常的命名空间规则适用。 Even though the client bundle on Node B has a reference to a service running in a bundle Node A, the service bundle in Node A cannot create (ie deserialize) an instance of a class that only exists in the client bundle on Node B. 即使节点B上的客户端捆绑包引用了在捆绑节点A上运行的服务,但是节点A中的服务捆绑包无法创建(即反序列化)仅存在于节点B上客户端捆绑包中的类的实例。

I switched up my interfaces so that ITrackerManager method does not take an ITracker arguement. 我切换了接口,以使ITrackerManager方法不会引起ITracker争执。 Instead it takes a string. 相反,它需要一个字符串。 Invoking that method over DOSGi works fine. 通过DOSGi调用该方法效果很好。

While I understand why this problem exists, this undermines a core capability I was hoping to use with DOSGi. 虽然我理解为什么存在此问题,但是这破坏了我希望与DOSGi一起使用的核心功能。 I want clients to be able to register with a central controller which will actively control them. 我希望客户能够向将主动控制他们的中央控制器注册。 This won't work because even though the clients implement the interface the central controller is looking for, the specific serialization fails at the central controller. 这将不起作用,因为即使客户端实现了中央控制器正在寻找的接口,特定的序列化在中央控制器上也会失败。 The client concrete classes exist in a namespace unknown to the central controller, hence the client cannot successfully pass itself to the central controller. 客户端具体类存在于中央控制器未知的名称空间中,因此客户端无法成功地将自身传递给中央控制器。

This must be a way to achieve what I am looking for in DSOGi without making each of the multiple clients an exported DSOGi service. 这必须是实现我在DSOGi中寻找的目标的一种方法,而不必使多个客户端中的每一个都成为导出的DSOGi服务。 Any ideas? 有任何想法吗?

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

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