【问题标题】:PaxExam OSGI Container and ServiceLookupExceptionPaxExam OSGI 容器和 ServiceLookupException
【发布时间】:2016-03-20 11:41:34
【问题描述】:

我已经构建了一个非常简单的包,它具有零依赖项并且不导入任何包。它的唯一内容是一个 CalculatorService 接口和对应的实现类,其中只包含一个简单的 add(int a, int b) 方法。

我为此包创建了两个 PaxExam 测试容器,一个使用 Karaf 容器,另一个使用 OSGI 容器。 Karaf 容器测试工作正常,但 OSGI 测试容器不能。

澄清一下...如果我将 CalculatorService 注入到 OSGI 测试容器中,并在我的 JUnit 测试用例中直接实例化 CalculatorServiceImpl 类,它就可以正常工作。所以我的简单包中的类对 OSGI 测试容器是可见的。

一些问题:

  • 我的 pom.xml 文件中是否缺少一些东西来完成这项工作?
  • 我应该向我的 OsgiTestClient.config() 方法添加更多包吗?
  • 其他关于保留内容的想法是非常精简的示例?

以下是我在尝试将 CalculatorService 注入我的 PaxExam OSGI 测试容器时得到的堆栈跟踪。

org.ops4j.pax.swissbox.tracker.ServiceLookupException: gave up waiting for service info.xyz.common.Calculator
    at org.ops4j.pax.swissbox.tracker.ServiceLookup.getService(ServiceLookup.java:199)
    at org.ops4j.pax.swissbox.tracker.ServiceLookup.getService(ServiceLookup.java:136)
    at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectField(ServiceInjector.java:89)
    at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectDeclaredFields(ServiceInjector.java:69)
    at org.ops4j.pax.exam.inject.internal.ServiceInjector.injectFields(ServiceInjector.java:61)
    at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.createTest(ContainerTestRunner.java:61)
    at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:68)
    at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.runChild(ContainerTestRunner.java:37)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.invokeViaJUnit(JUnitProbeInvoker.java:124)
    at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.findAndInvoke(JUnitProbeInvoker.java:97)
    at org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker.call(JUnitProbeInvoker.java:73)
    at org.ops4j.pax.exam.nat.internal.NativeTestContainer.call(NativeTestContainer.java:112)
    at org.ops4j.pax.exam.spi.reactors.AllConfinedStagedReactor.invoke(AllConfinedStagedReactor.java:84)
    at org.ops4j.pax.exam.junit.impl.ProbeRunner$2.evaluate(ProbeRunner.java:267)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.ops4j.pax.exam.junit.impl.ProbeRunner.run(ProbeRunner.java:98)
    at org.ops4j.pax.exam.junit.PaxExam.run(PaxExam.java:93)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

包含计算器服务的简单包的 pom.xml 如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>info.xyz</groupId>
    <artifactId>xyz-businessLogic</artifactId>
    <version>0.0.1</version>
    <packaging>bundle</packaging>

    <dependencies>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Import-Package>
                        </Import-Package>
                        <Export-Package>
                            info.xyz.common,
                            info.xyz.common.impl
                        </Export-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

很明显,我的简单包的依赖项为零,并且导出了包含 Calculator 和 CalculatorImpl 文件的包。下面是定义这些服务的 blueprint.xml 文件。

<?xml version="1.0" encoding="UTF-8"?>
<blueprint default-activation="eager" xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.0.0"

    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0 
            http://www.w3.org/2001/XMLSchema-instance http://www.w3.org/2001/XMLSchema-instance 
            http://aries.apache.org/xmlns/jpa/v1.0.0 http://aries.apache.org/xmlns/jpa/v1.0.0 
            http://aries.apache.org/xmlns/transactions/v1.0.0 http://aries.apache.org/xmlns/transactions/v1.0.0">

    <bean id="calculatorService" class="info.xyz.common.impl.CalculatorImpl" />
    <service ref="calculatorService" interface="info.xyz.common.Calculator" />
</blueprint>

接下来,我的 PaxExam OSGI 容器的 pom.xml 如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>info.xyz</groupId>
    <artifactId>xyz-test-osgi</artifactId>
    <version>0.0.1</version>

    <parent>
        <groupId>info.xyz</groupId>
        <artifactId>xyz</artifactId>
        <version>0.0.1</version>
        <relativePath>../xyz</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-container-native</artifactId>
            <version>${pax.exam.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-junit4</artifactId>
            <version>${pax.exam.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-link-mvn</artifactId>
            <version>${pax.exam.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.url</groupId>
            <artifactId>pax-url-aether</artifactId>
            <version>${pax.url.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam</artifactId>
            <version>${pax.exam.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-inject</artifactId>
            <version>${pax.exam.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.framework</artifactId>
            <version>5.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${ch.qos.logback.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${ch.qos.logback.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>${javax.inject.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Testing target -->
        <dependency>
            <groupId>info.xyz</groupId>
            <artifactId>xyz-businessLogic</artifactId>
            <version>0.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Needed if you use versionAsInProject() -->
            <plugin>
                <groupId>org.apache.servicemix.tooling</groupId>
                <artifactId>depends-maven-plugin</artifactId>
                <version>1.3.1</version>
                <executions>
                    <execution>
                        <id>generate-depends-file</id>
                        <goals>
                            <goal>generate-depends-file</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

最后给出OSGI Test类如下:

package info.xyz.test.osgi;

import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import info.xyz.common.Calculator;

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.ProbeBuilder;
import org.ops4j.pax.exam.TestProbeBuilder;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerMethod;
import org.osgi.framework.Constants;

@RunWith(PaxExam.class)
@ExamReactorStrategy(PerMethod.class)
public class OsgiTestClient
{
    @Inject
    protected Calculator _calculator;

    @ProbeBuilder
    public TestProbeBuilder probeConfiguration(TestProbeBuilder probe)
    {
        System.out.println("TestProbeBuilder gets called");
        probe.setHeader(Constants.DYNAMICIMPORT_PACKAGE, "*");
        probe.setHeader(Constants.IMPORT_PACKAGE, "info.xyz.common");
        probe.setHeader(Constants.IMPORT_PACKAGE, "info.xyz.common.impl");
        return probe;
    }

    @Configuration
    public Option[] config()
    {
        return new Option[] {
                junitBundles(),
                mavenBundle().groupId("info.xyz").artifactId("xyz-businessLogic").versionAsInProject(),
        };
    }

    @Test
    public void testAdd()
    {
        info.xyz.common.impl.CalculatorImpl calculator = new info.xyz.common.impl.CalculatorImpl();
        int result = calculator.add(1, 2);
        System.out.println("--- testing: ");
    }
}

最后一条注释,如果我注释掉注入 CalculatorService 的代码,代码运行良好(因为我手动实例化了 CalculatorImpl 类)。因此,我的测试容器确实对 Calculator 接口和实现具有编译时和运行时可见性。但是注入此服务不起作用。

最后提醒一下,当我构建 PaxExam Karaf 测试容器时,Calculator 服务的注入是成功的,并且测试用例运行良好。错误是在运行本文中描述的 PaxExam OSGI 容器时发生的。

【问题讨论】:

  • 您能否提供有关如何在您的计算器示例中注册/发布服务的更多信息?我的意思是您使用声明式服务或蓝图还是使用 OSGi 方法(ServiceTracker、registerServices...)
  • 好点...我已将 blueprint.xml 添加到原始帖子中。

标签: maven junit osgi pax-exam


【解决方案1】:

是的,那就是蓝图堆栈/库默认没有安装在本机容器中(但它们在 Karaf 中)。

您需要将此 deps 添加到您的测试 pom:

    <dependency>
        <groupId>org.apache.aries</groupId>
        <artifactId>org.apache.aries.util</artifactId>
        <version>1.1.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.aries.proxy</groupId>
        <artifactId>org.apache.aries.proxy.api</artifactId>
        <version>1.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.aries.proxy</groupId>
        <artifactId>org.apache.aries.proxy.impl</artifactId>
        <version>1.0.4</version>
    </dependency>


    <dependency>
        <groupId>org.apache.aries.blueprint</groupId>
        <artifactId>org.apache.aries.blueprint.api</artifactId>
        <version>1.0.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.aries.blueprint</groupId>
        <artifactId>org.apache.aries.blueprint.core</artifactId>
        <version>1.4.2</version>
    </dependency>

    <dependency>
        <groupId>org.apache.aries.blueprint</groupId>
        <artifactId>org.apache.aries.blueprint.core.compatibility</artifactId>
        <version>1.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.aries.blueprint</groupId>
        <artifactId>org.apache.aries.blueprint.cm</artifactId>
        <version>1.0.5</version>
    </dependency>

并在您的测试中将以下捆绑包添加到您的配置中:

mavenBundle().groupId("org.apache.aries").artifactId("org.apache.aries.util").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.proxy").artifactId("org.apache.aries.proxy.api").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.proxy").artifactId("org.apache.aries.proxy.impl").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.api").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.cm").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.core").versionAsInProject(),
                    mavenBundle().groupId("org.apache.aries.blueprint").artifactId("org.apache.aries.blueprint.core.compatibility").versionAsInProject().noStart(),

这应该可以解决问题!

【讨论】:

  • 成功了...感谢您的宝贵时间,非常感谢。
猜你喜欢
  • 2016-03-23
  • 2014-03-02
  • 2012-05-02
  • 2018-12-26
  • 2011-03-09
  • 2011-06-30
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
相关资源
最近更新 更多