OSGi 包导出版本控制

OSGi bundle export versioning

我是 osgi 世界的新手,可能遗漏了一些东西,而且我在为 liferay 公开同一服务的不同版本时遇到了麻烦。

这是我正在尝试做的事情(对不起我的英语):

我编写了一个服务,将其打包并成功部署到 osgi 上。我的 bnd.bnd 文件看起来像这样

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

并且,一旦打包,manifest文件是这样的

Manifest-Version: 1.0
Bnd-LastModified: 1542646653910
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
 esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
 .0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
 o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
 ,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
 do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
 on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
 ",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
 .8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
 work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
 x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
 network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
 n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
 n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
 ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
 network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007

此清单文件声明

Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"

我认为这是正确的。

部署(成功)后,我使用命令 bundle __BUNDLE_ID__ 检查捆绑包状态

pilot--test-services_7.1.0 [1014]
  Id=1014, Status=ACTIVE      Data Root=/home/ltrioschi/development/liferay-osgi/liferay-ce-portal-7.1.0-ga1/osgi/state/org.eclipse.osgi/1014/data
  "Registered Services"
    {it.peernetwork.lr.pilot.testservices.UselessService}={service.id=1607, service.bundleid=1014, service.scope=singleton}
  No services in use.
  Exported packages
    it.peernetwork.lr.pilot.testservices; version="7.1.0"[exported]
  Imported packages
    com.liferay.expando.kernel.exception; version="1.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.expando.kernel.model; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.expando.kernel.service; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.exception; version="7.2.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    com.liferay.portal.kernel.model; version="2.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
    org.osgi.framework; version="1.8.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
  No fragment bundles
  No required bundles

然后我写了一个需要这个服务的 portlet。 bnd.dnd 文件是

Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0

Import-Package: \
    it.peernetwork.lr.pilot.testservices;version=[7.1.0],\
    *

-metatype: *

部署后,它会正确加载服务并毫无问题地使用它。

现在...我的问题是我需要一个新版本的服务,但我不想取消部署当前版本。

所以我写了新版本的服务,新的bnd.bnd文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.1
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

(唯一的区别是Bundle-Version

打包后清单文件中的唯一区别是 Export-Package

Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.1"

看起来它在 osgi 上顺利部署

g! lb pilot
START LEVEL 20
   ID|State      |Level|Name
 1014|Active     |   10|it.peernetwork.lr.pilot.test-services (7.1.0)
 1015|Active     |   10|it.peernetwork.lr.pilot.test-services (7.1.1)

但是使用命令 bundle ___NEW_BUNDLE_ID___ 我得到

No exported packages

而不是

Exported packages
  it.peernetwork.lr.pilot.testservices; version="7.1.1"[exported]

(如我所料)。这意味着(对我而言)捆绑包已部署,但其服务的 none 已公开。

然后我以这种方式更新了我的 portlet 包 (bnd.bnd)

Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0

Import-Package: \
    it.peernetwork.lr.pilot.testservices;version=[7.1.1],\
    *

-metatype: *

(在 Import-Package 中更改了版本)并部署在 osgi 上。部署是正确的,但它仍然使用旧版本的服务包 (7.1.0),即使 Import-Package 声明版本 7.1.1。由于 "missing" 请求的服务版本,它不会给出错误。

有人可以告诉我一些关于我做错了什么的提示吗?

提前致谢。


更新 1

build.gradle 文件中的依赖项已相应更新为 bnd.bnd 中指定的版本。


更新 2

@quatax

更新后的 portlet 包的清单文件有 Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.1.1]"(后跟所有其他必需的导入)...对我来说似乎是正确的...


更新 3

@Neil Bartlett(服务版本更新到8.0.0)

我更新了 pilot--test-services bnd.bnd 文件设置 Bundle-Version: 8.0.0。 整个 bnd.bnd 文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

清单文件是

Manifest-Version: 1.0
Bnd-LastModified: 1543316524201
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
 esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
 .0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
 o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="8.0.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
 ,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
 do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
 on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
 ",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
 .8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
 work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
 x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
 network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
 n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
 n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
 ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
 network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007

。当我部署它时它似乎没问题(启动和状态是 "Active"),但是 bundle ___ID___No exported packages

然后我更新了 pilot--test-portletbuild.gradle 设置依赖项的正确版本 (8.0.0)。它的清单文件显示 Import-Package: it.peernetwork.lr.pilot.testservices;version="[8.0,9)。当我部署这个包时它没有启动(状态 "Installed" 和错误 Unresolved requirement: Import-Package: it.peernetwork.lr.pilot.testservices; version="[8.0.0,9.0.0)"


更新 4 -- -- 已解决 非常感谢@Neil。感谢您的提示,我解决了我的问题。正确的建议是

明确声明

Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
        *

pilot--test-servicesbnd.bnd 文件中(自导入,具有适当的版本范围)使 osgi 正确导出包并在需要时加载正确的 class 实例。

完整的 bnd.bnd 文件是

Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.2.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices

Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
        *

pilot--test-portletbuild.gradle文件中我只需要更新依赖版本

compileOnly group: "it.peernetwork.lr", name: "pilot--test-services", version: "7.2.0"

我尝试了 7.1.0、7.2.0 和 8.0.0 版本,运行顺利。所有 "services" 包都部署在 osgi 上。部署具有不同依赖项版本的 portlet 包始终采用正确的服务。

再次感谢。

我建议从 bnd.bnd 文件中删除 pilot--test-portlet 包的 Import-Package 指令。不是必须的:bnd会根据你代码中的实际需求生成你需要的所有导入。

您的原始包 pilot--test-services 导出和导入包 it.peernetwork.lr.pilot.testservices。当您的包除了导出包之外还使用包本身时,这是正确的。因此,当您同时安装 v7.1.0 和 v7.1.1 时,v7.1.0 包将从其他版本导入包,而不是导出旧版本。 pilot--test-portlet 从版本 7.1.1 正确导入。

换句话说,这里的一切都在按应有的方式运行。