检测 (Eclipse) OSGI 错误“使用冲突”
解决有冲突的大型捆绑树是一项乏味的工作。
最容易解决的错误是“缺少约束”。这只是缺少包或类,错误明确说明缺少哪个 java 包/包。
我要关注的是神秘的 OSGI 错误消息,称为“uses-conflict”。
Equinox OSGI 工具没有提供太多关于造成版本冲突的包名的信息。那里有很多论文解释了如何解决冲突,但是,没有一篇显示如何快速找到发生冲突的包。
这是一种确定哪个包+版本导致冲突的方法。
我们将从一些虚构的项目开始:一个开发人员编写了一个 Eclipse 插件 + 几个包 (JAR)。
该插件主要包含 UI 代码,而 JAR 主要包含共享/可重用逻辑。
开发人员将它们全部打包到一个 Eclipse 功能中并尝试安装它。
由于“使用冲突”,插件无法启动。
你有一个插件。您安装但由于“使用冲突”而无法启动
关闭日食。
通过命令行(linux)重新运行eclipse:
./eclipse -console -consoleLog -data /tmp/eclipseTest/workspace/ -clean
(win32 用户当然应该调用 eclipse.exe)
该命令将打开我们稍后需要的 osgi 控制台。
当 eclipse 加载完成后,切换回 eclipse 命令行窗口。您应该会看到“osgi>”命令提示符(如果没有按两次 Enter)
找到你的 plugin/bundles 的 Java 包。假设它被命名为 com.A , B, C , D 和 E
在 osgi 控制台中运行:
osgi> ss com.A
id State Bundle
7 INSTALLED com.A
osgi> start 7
org.osgi.framework.BundleException:无法解析捆绑包“com.A [7]”。原因:包使用冲突:Require-Bundle: com.B;捆绑版本="0.0.0"
在 org.eclipse.osgi.framework.internal.core.AbstractBundle.getResolverError... 更多堆栈在这里...
现在我们知道 com.A 依赖于 bundle com.B 的 bundle 和 com.B 有冲突。原因当然是营养用途冲突。 (旁注:实际的冲突可能会被进一步隐藏:在 com.B 所依赖的其他捆绑包中,但现在让我们忽略这一点)
我们希望达到的理想状态是:
osgi> ss com.A
Framework is launched.
id State Bundle
7 ACTIVE com.A
但我们还没有。
所以我们知道 bundle com.B 是有问题的。
我们可以通过运行查看它尝试加载(但失败)的导入列表
osgi> bundle 10
(10 是我们的 com.B 包从 OSGI 容器中获取的随机包 ID。只需在 osgi 控制台中运行:“ss com.B”即可找到它的包 ID)
关注“导入包”部分。把它复制到某个地方。
在将插件安装到 Eclipse 框架时,它实际上被解压缩到 Eclipse 的插件目录中。打开文件资源管理器并转到 /plugins 。找到“坏”包的目录(解决“使用冲突”的那个)它可能会被命名为 com.B.[version_or_timestamp]。
深入到 META-INF 目录。编辑 manifest.mf:首先清理 Import-packages 部分(将该部分剪切粘贴到记事本)
重启eclipse(Ctrl+C退出osgi控制台中运行的eclipse然后重新运行)
现在 eclipse 应该说 bundle 是“活动的”。如果它没有在活动模式下启动,它可能会遇到 Missing-Constraint 错误。这很容易解决,因为错误信息量很大,但这不是这里的重点。
直到 uses-conflict re-pop:开始将该清单中的 Import-packages 部分重新填充到其原始状态。一次只做一个 java 包,这样您就可以查明导致“使用冲突”的更改
在记事本中编辑 manifest.mf 时,请确保在第 71 列按 Enter,并且下一行以单个空格开头。您可能已经注意到,清单具有您必须遵循的独特的换行结构。
重启 Eclipse(在 osgi 控制台中按 Ctrl+C 然后重新运行)。
通过运行 osgi 命令“ss com.A”重新测试捆绑包状态,尝试“start com.A”并查看是否出现任何错误。
在每次 manifest.mf 更改后重新启动 eclipse。
将错误的 java 导入添加到 manifest.mf 后,您将看到捆绑包仅标记为“已解决”(而不是活动的)。
让我们假设您发现的第一个破坏捆绑包的 java 包是 javax.xml.bind。
在 OSGI 控制台运行:“packages javax.xml.bind”,您应该会看到该命名空间的已解析 OSGI 捆绑包+版本+使用的列表。如果您有多个提供程序(即多个版本 - 它是一棵树。查看它的根),您可能需要更改原始包并强制它导入特定版本(通过使用 Import 中的“version”指令-Package 部分。例如 javax.xml.bind;version="[2.1,3)" 这是告诉 osgi 搜索范围)
通常,如果您编写 OSGI 包或 Eclipse 插件,最佳实践是尽可能在 Import-package 标头中明确指定 Import 版本范围(并且不要使用默认值,即 0.0.0 或任何版本)。同样的规则也适用于有时在 Import-Package 标头中使用的 uses:= 指令。
同样适用于 Require-Bundle 标头:最好使用“bundle-version”OSGI 指令来确保您获得所需的版本。
如果在构建过程中使用 Maven,它就更重要了,因为它允许 maven 正确计算版本依赖关系(尤其是在使用 Felix maven-bundle-plugin 时)
另一个问题是有时你确实需要在你的 bundle 清单中:
导入包:javax.xml.bind;version=”[2.1.9,3)”
但由于某种原因,这不能满足。如果可能的话,您可以将您的版本范围扩大到更广泛的版本。
当您解决您的 OSGI 冲突时,不要忘记相应地编辑您的原始构建清单/脚本。
旁注:您也可以尝试运行“eclipse.exe -clean”,它可能会正确地重新计算捆绑包依赖项并让您的插件启动,但这不是一个长期的解决方案。