包使用冲突:捆绑启动时的Import-Package

时间:2011-03-31 17:50:15

标签: osgi

尝试安装htmlunit软件包时出现以下错误:

com.springsource.com.gargoylesoftware.htmlunit_2.6.0 [370] could not be resolved.
  Reason: Package uses conflict: 
  Import-Package: org.apache.commons.logging.impl; version="1.1.1"

我已在this blog上遵循此类问题的诊断程序。

以下是我的发现: 捆绑com.springsource.com.gargoylesoftware.htmlunit_2.6.0具有以下说明:

Import-Package: \
  org.apache.commons.logging;version="[1.1.1, 2.0.0)",\
  org.apache.commons.logging.impl;version="[1.1.1, 2.0.0)"

在我的OSGi中使用约束的唯一包是com.springsource.org.apache.commons.logging,其中包含以下指令:

Export-Package: \
  org.apache.commons.logging;version="1.1.1",\
  org.apache.commons.logging.impl;version="1.1.1";\
    uses:="javax.servlet,
           org.apache.avalon.framework.logger,
           org.apache.commons.logging,
           org.apache.log,
           org.apache.log4j"

Import-Package: \
  javax.servlet;version="[2.1.0, 3.0.0)";resolution:=optional,\
  org.apache.avalon.framework.logger;version="[4.1.3, 4.1.3]";resolution:=optional,\
  org.apache.log;version="[1.0.1, 1.0.1]";resolution:=optional,\
  org.apache.log4j;version="[1.2.15, 2.0.0)";resolution:=optional   

此时我陷入困境,因为我无法弄清楚问题是什么以及如何解决问题,尽管我从上面提供的内容应该很明确,但不是我:(

任何想法......?

2 个答案:

答案 0 :(得分:13)

这很可能与'import-what-you-export'有关。

uses约束声明“如果要导入此包,请更好地确保使用与我相同的包”,这不仅意味着包的版本,而且相同的包,由同一捆绑包导出。 您的第二个捆绑包会导出logginglogging.impl个包,说明“如果您要使用logging.impl,请使用与我相同的logging,并且它也会发生在出口一个。这意味着,任何想要导入logging.impl 的人也必须从您的包中导入logging,因为它无法连接到任何其他logging包。 如果框架中有另一个logging副本,这会导致问题,这可能会在之前得到解决。

解决此问题的最简单方法可能是将logging添加到第二个捆绑包的Import-Package。这样,您可以选择使用哪个包直到框架。

在一个不相关的说明中,除去所有";resolution:=optional语句,除非你的代码可以真正适用于某些包不可用的情况。我很惊讶你的捆绑可以在没有javax.servlet的情况下工作。

答案 1 :(得分:8)

检测(Eclipse)OSGI错误“使用冲突” 解决一个有冲突的大捆树是一项繁琐的工作。 最容易解决的错误是“缺少约束”。这只是一个缺少的bundle或类,错误明确指出缺少哪个java包/ bundle。 我想要关注的是名为“uses-conflict”的神秘的OSGI错误消息。 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键两次)     找到插件/包的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和com.B的bundle有冲突。原因当然是营养用途冲突。 (旁注:实际冲突可能会进一步隐藏:在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是“ACTIVE”。如果它没有以活动模式启动,它可能会遇到Missing-Constraint错误。这很容易解决,因为错误信息非常丰富,但这不是重点。

  • 在uses-conflict重新弹出之前:开始将该清单中的Import-packages部分重新填充到其原始状态。一次做一个java包,这样你就可以确定哪个更改导致“使用冲突”

  • 在记事本中编辑manifest.mf时,请确保在第71列按Enter键,下一行以单个空格开头。您可能已经注意到,清单具有您必须遵循的独特新线结构。

  • 重新启动eclipse(在osgi控制台中按Ctrl + C然后重新运行)。

  • 通过运行osgi命令“ss com.A”重新测试捆绑状态“尝试”启动com.A“并查看是否有任何错误。

  • 在每个manifest.mf如上所述更改后重新启动eclipse。

将错误的java导入添加到manifest.mf后,您将看到该包仅标记为“已解决”(而不是活动)。 让我们假设你发现破解捆绑包的第一个java包是javax.xml.bind。 在OSGI控制台上运行:“package javax.xml.bind”,您应该看到已解析的OSGI包的列表+该命名空间的版本+用法。如果您有多个提供程序(即多个版本 - 它的树。查看其根目录),您可能需要更改原始包并强制它导入特定版本(通过使用Import中的“version”指令-Package部分。例如javax.xml.bind; version =" [2.1,3)"这告诉osgi搜索范围) 通常,如果您编写OSGI包或Eclipse插件,最佳做法是在可能的情况下明确指定导入版本范围(并且不使用默认值,即0.0.0或任何版本)。同样的规则也适用于uses:=有时在Import-Package标头中使用的指令。

同样适用于Require-Bundle标头:最好使用“bundle-version”OSGI指令来确保获得所期望的版本。 如果Maven在构建过程中使用它更重要,因为它允许maven正确计算版本依赖性(特别是如果使用Felix maven-bundle-plugin)

另一个问题是,有时你会在你的包的清单中提出要求: Import-Package:javax.xml.bind; version =“[2.1.9,3)” 但由于某种原因,这不能令人满意。如果可能,您可以将版本范围扩展到更宽的范围。

解决OSGI冲突后,请不要忘记相应地编辑原始构建清单/脚本。

侧评:您也可以尝试运行“eclipse.exe -clean”,这可能会正确地重新计算软件包依赖关系并让您的插件启动,但这不是一个长期的解决方案。

相关问题