我正在试图弄清楚如何使用JUnit在OSGi中实现多束集成测试.
使用集成测试,我的意思是实例化bundle的子集以自动验证该子系统中的功能.
我们正在运行Equinox并使用Eclipse作为工具链.Eclipse提供了"Run as JUnit Plug-in"选项,它带来了OSGi框架并实例化了配置包,所以我想这是要遵循的路径,但我找不到将DS引用注入我的测试的方法.我已经看到使用ServiceTracker作为一种程序化方法来访问不同的服务包,但这比使用DS的目的要好,不是吗?
我刚刚开始使用OSGI,所以我想我只是错过了一些让我将多束测试结合在一起的难题.
有任何想法吗?
谢谢,杰拉德.
*编辑:解决方案*
在深入研究这个问题之后,我终于想出了如何使用JUnit插件功能来实现这种多包集成测试:
要使动态服务注入工作,必须创建一个服务定义文件,其中必须声明注入的依赖项,因为它通常在使用DS时完成.该文件(通常)在OSGI-INF/目录下.例如OSGI-INF/service.xml
service.xml必须声明此测试所需的依赖项,但不提供自己的服务:
service.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown">
<implementation class="com.test.functionaltest.MyTester"/>
<reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/>
</scr:component>
Run Code Online (Sandbox Code Playgroud)
这将指示DS使用声明的onServiceUp方法注入对FooService的依赖.onServiceDown必须在运行测试后在OSGi关闭阶段调用时实现.
com.test.functionaltest.MyTester包含要执行的测试方法,遵循典型的JUnit实践.
到目前为止,这一切都在"书中".但是,如果运行Junit,则在访问对FooService的引用时会抛出NullPointerException.原因是OSGi框架处于竞争状态,JUnit测试运行器上下文,通常,Junit测试运行器赢得该竞赛,在注入所需服务的引用之前执行测试.
要解决这种情况,需要使Junit测试等待OSGi运行时执行其工作.我使用CountDownLatch解决了这个问题,它被初始化为测试中所需的依赖服务的数量.然后每个依赖注入方法倒计时,当它们全部完成时,测试将开始.代码如下所示:
private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required
static FooService fooService = null;
public void onFooServiceUp(FooService service) {
fooService = service;
dependencyLatch.countDown();
}
Run Code Online (Sandbox Code Playgroud)
请注意,fooService引用需要是静态的,以允许在OSGi和JUnit执行上下文之间共享服务引用.CountDownLatch提供了一个高级同步机制,用于安全发布此共享引用.
然后,应在测试执行之前添加依赖性检查:
@Before
public void dependencyCheck() {
// Wait for …Run Code Online (Sandbox Code Playgroud) 我最近偶然发现,OSGi中的Declarative Services可以将组件的配置设置为必需,以便组件在激活时接收它,消除组件激活和配置之间的差距.我也意识到你可以通过modified-method 接收配置更新.
在我看来,这个功能非常类似于通过实现ManagedService接口和发布作为您提供的"服务"之一提供的功能.
看起来我可以完全忽略ManagedService并只使用DS配置注入.
这些技术中的一种比其他技术更受欢迎,还是还有其他我没有看到的权衡取舍?
我创建了一个带有暴露(声明)服务的OSGi包.如果我,当调用激活时,注意到某些东西是不对的,这样我就无法提供服务,我需要防止它暴露.目前激活功能如下:
public void activate(ComponentContext context, Map<String, Object> properties) {
pid = (String) properties.get(Constants.SERVICE_PID);
try {
...
}
catch(Exception e) {
context.disableComponent(pid);
}
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是只包装/传播异常(或抛出一个新异常,取决于),如下所示:
public void activate(ComponentContext context, Map<String, Object> properties) {
try {
...
}
catch(Exception e) {
throw new ComponentException("Some reason");
}
}
Run Code Online (Sandbox Code Playgroud)
我找不到OSGi Service Platform Service Compendium中关于声明性服务的部分中指定的正确行为,但我可能会遗漏某些内容
我有这个场景,我有三个声明性服务,提供相同的接口(比如一个读者接口,我有readerimpl1-database- readerimpl2-flat file- readerimpl3-memory).我希望有一个只绑定到数据库实现的使用者.在组件定义中,我们给它一个名称,所以我很确定名称在注册表中,所以如果我要添加一个activate方法,我可以使用名称从组件上下文中查找.
我想通过bind/unbind尝试使用服务名称作为参数.我很确定组件引用元素中的"target"参数可用于执行此操作,但我还没有找到如何使用它.
还有其他人这样做过吗?
这与使用@Reference(mapped-name ="foo")类似
我在我的应用程序中使用Apache Felix声明性服务,我正在寻找一个描述可以给@Reference注释的参数的备忘单.我看过一个网页,其中包含一个非常丰富的备忘单(或表格),但我似乎无法找到它.我认为这对很多Felix用户来说都很有用.我正在谈论的参数:
MANDATORY_UNARY, MANDATORY_MULTIPLE, OPTIONAL_UNARY, OPTIONAL_MULTIPLEEVENT, LOOKUPDYNAMIC, STATICGREEDY, RELUCTANT基数相当简单,但其他人对我来说并不清楚.他们做了什么以及他们如何运作?
我偶然发现了代码中的一个现象,可以归结为:
我有一个OSGi声明服务,提供了两个配置如下的服务接口:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="dispose" enabled="true" name="redacted.redactedstore">
<implementation class="redacted.RedactedStore"/>
<service>
<provide interface="redacted.IRedactedStore"/>
<provide interface="redacted.IRedactedStoreControl"/>
</service>
</scr:component>
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我有两个不同的线程,它们都打开a ServiceTracker来获取服务实例,但是通过不同的接口:
tracker = new ServiceTracker<>(getBundle().getBundleContext(), <serviceClass>.class, null);
tracker.open();
tracker.waitForService(1000l);
Run Code Online (Sandbox Code Playgroud)
因此,一个线程IRedactedStore用作服务类,另一个线程IRedactedStoreControl用作服务接口。
因此,似乎发生的事情是,当两个线程在正确的时间并行运行时,Equinox SCR不会实例化一个(如我期望的那样),而是实例化组件实现类的两个实例。
这种行为正确吗?还是这是OSGi的Equinox实现中的错误?
如果行为正确,那么我可以在代码中做一些事情来通过另一种方式配置服务来防止这种情况吗?(当然,我可以重组服务,以便它仅提供一个接口,或者可以同步服务跟踪器...)
我有一个片段包,我创建它来访问第二方jar的一些添加功能.我的片段应该注册一个服务来公开这个新功能.它似乎不起作用.在深入了解故障排除之前,我想知道是否允许这样做?也就是说,Felix SCR的捆绑监视器会查看还是忽略片段?
OSGi企业版第5版规范引入了osgi.extender命名空间.此命名空间使得可以在框架中安装假定扩展程序(如Blueprint或Declarative Services)的bundle,以使用Require-Capability标头对此依赖项进行建模.
第135.2章osgi.extender命名空间告诉我们应该在相应的规范中指定每个特定扩展器的功能值.蓝图给出了一个例子:
Provide-Capability: osgi.extender;
osgi.extender="osgi.blueprint";
uses:="org.osgi.service.blueprint.container,org.osgi.service.blueprint.reflect"
version:Version="1.0"
Run Code Online (Sandbox Code Playgroud)
但是,第112章声明性服务规范未指定SCR实现提供的功能.
Peter Kriens在一篇关于需求和能力的博客文章中给出了一个例子,该文章暗示了SCR的能力osgi.component.我假设最终这个值将在规范中正确定义.但在那之前我不能使用它.
由于在OSGi Core Release 4.3中引入了Require-Capability和Provide-Capability头文件,因此框架实现中已经可以使用该机制.因此,我希望我的bundle能够表达对SCR的要求,以便可以从OBR存储库中解析SCR实现.
我可以想象一个解决方案,我创建一个空包,一方面提供自定义功能,另一方面需要一个实现包.例如:
Provide-Capability: com.example.extender; extender=scr
Require-Bundle: org.apache.felix.scr; bundle-version=1.6.0
Run Code Online (Sandbox Code Playgroud)
然后,任何包含声明性服务的bundle都可以表达对此功能的要求.例如:
Require-Capability: com.example.extender; filter:="(extender=scr)"
Run Code Online (Sandbox Code Playgroud)
当我部署包含声明性服务的bundle时,这是确保SCR得到解决的好方法吗?还有其他方法吗?
这个问题的一个很好的解决方案是一个解决方案,也可以应用于其他不提供功能的传统捆绑包.
我正试图在广阔的企业OSGi编程生态系统中感到舒服,但我发现很难概述这个技术堆栈是如何组合在一起的,哪些技术相互依赖,哪些技术解决了什么任务,以及如何它们都符合我迄今为止所理解的有限术语.
例如:Apache Felix,Equinox,Karaf,Jira OSGi,Spring DM,Aries Blueprint,Gemini Blueprint,iPOJO,Camel等之间的关系是什么......
我知道Equinox基于Felix,而Blueprint变体和iPOJO在某种程度上与组件管理有关,但是声明服务呢?DS是Blueprint的替代品,还是Blueprint是Declarative Services的实现?
总的来说,我很困惑,我真的需要简单概述一般OSGi技术的相关性.
有谁知道OSGi生态系统存在这样的概述 - 也许是图形化的?
最好的祝福.
我有一个相当复杂的 OSGi 应用程序,它使用声明式服务,并且设计为部署在 Equinox 中。现在的任务是使该应用程序可以部署在 WAS 8 中。
第一次尝试非常务实:我部署了一个 EAR,它的启动基本上与 Equinox 相同,经过一些 WAS 类加载策略调整后,它已经起作用了。
现在我想更进一步:摆脱 Equinox 运行时并在 WAS 8 中“本地”部署我的捆绑包。因此,我编写了一个 EBA,其中包含我的业务捆绑包、它们的依赖项和 Equinox DS 运行时。EBA 作为资产部署并集成到 BLA 中。应用程序甚至已启动并运行,但组件尚未初始化。
要点是,必须在自己的业务包之前启动 equinox.ds(更新:不是必须的,下面讨论)才能使 DS 完成其工作。但是我如何告诉捆绑包在已部署的 EBA 中首先启动哪个捆绑包呢?我需要 Equinox 的 config.ini 文件的一些模拟。
我知道我可以使用本机支持的蓝图重新连接我的组件,但坦率地说,这是我最不想做的事情。应该可以让 Equinox DS 工作,不是吗?
另一个问题是:如何为自己部署在 WAS 8 下的应用程序获取 OSGi 控制台?我想控制我的捆绑包,但似乎无法从管理控制台做到这一点。
更新
感谢 BJ 和 Neil(下面的讨论),问题归结为“如何在 WAS 8.0 中部署的我自己的 OSGi 应用程序中启动特定的包?”
osgi ×9
java ×4
apache-felix ×3
equinox ×3
eclipse-rcp ×1
jira ×1
junit ×1
osgi-bundle ×1
websphere-8 ×1