Serg M Ten
Serg M Ten

Reputation: 5606

How can I programmatically get beans from an OSGI blueprint?

For test purposes, I would like to get an instance of the beans in the blueprint of an Apache Camel application.

Inside a JUnit test, how can I get an instance of the beans at daos.xml below as they will exist in the OSGI container of the application?

Kind of

AuditPageNavDao aDao = Daos.getInstance("auditPageNavDao");

I've got a Maven pom.xml with a plugin:

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Bundle-Name>DaoServicesCommon</Bundle-Name>
            <Bundle-Activator>com.acme.dao.bundle.Activator</Bundle-Activator>
            <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>
            <Import-Package>
                javax.persistence,
                org.hibernate.proxy,
                javassist.util.proxy,
                *
            </Import-Package>
        </instructions>
    </configuration>
</plugin>

META-INF/persistence.xml looks like

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

    <persistence-unit name="appPU" transaction-type="JTA">
        <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/appxadb)</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="hibernate.enable_lazy_load_no_trans" value="true" />
            <property name="show_sql" value="true" />
        </properties>
    </persistence-unit>

</persistence>

and OSGI-INF/blueprint/daos.xml looks like

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.1.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
        http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint-2.8.0.xsd
        http://aries.apache.org/xmlns/transactions/v1.2.0 http://aries.apache.org/schemas/transaction/transactionv12.xsd
        http://aries.apache.org/xmlns/jpa/v1.1.0 http://aries.apache.org/schemas/jpa/jpa_110.xsd">

    <!-- AUDIT DAO SERVICES -->
    <bean id="auditAccountTxnDao" class="com.acme.dao.audit.jta.AuditAccountTxnDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditAccountTxnDao"
        ref="auditAccountTxnDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditAccountTxnDao" />
        </service-properties>
    </service>

    <bean id="auditAuthDao" class="com.acme.dao.audit.jta.AuditAuthDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditAuthDao"
        ref="auditAuthDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditAuthDao" />
        </service-properties>
    </service>

    <bean id="auditPageNavDao" class="com.acme.dao.audit.jta.AuditPageNavDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditPageNavDao"
        ref="auditPageNavDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditPageNavDao" />
        </service-properties>
    </service>

    <bean id="auditTxnDao" class="com.acme.dao.audit.jta.AuditTxnDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditTxnDao"
        ref="auditTxnDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditTxnDao" />
        </service-properties>
    </service>

    <bean id="auditEventCodeDao" class="com.acme.dao.audit.jta.AuditEventCodeDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditEventCodeDao"
        ref="auditEventCodeDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditEventCodeDao" />
        </service-properties>
    </service>

</blueprint>

and last the Activator is

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator
{

    @Override
    public void start(final BundleContext context) throws Exception
    {
    }

    @Override
    public void stop(final BundleContext context) throws Exception
    {
    }

}

Upvotes: 1

Views: 2472

Answers (2)

Christian Schneider
Christian Schneider

Reputation: 19626

For pax exam I recommend to directly inject the service. Using The class from Alessandro as base.

@RunWith(PaxExam.class)
class YourTest {

    @javax.inject.Inject
    protected AuditPageNavDao dao;

    @Test
    testMethod() {
       // use DAO here
    }
}

This has the advantage that your @Test method will be executed as soon as the service is present in the system. In the variant from Alessandro your test might be executed before the service is there resulting in a NPE.

Be aware though that this approach only works for services. You can not simply get any blueprint bean in this way.

If you need individual beans you can inject the BlueprintContainer service like above. Each bundle that uses blueprint will have such a service. You can filter by the service property to get the BlueprintContainer of a specific bundle. Then use this to get a bean.

dao = container.getComponentInstance("auditAuthDao");

Upvotes: 1

Alessandro Da Rugna
Alessandro Da Rugna

Reputation: 4695

This depends on how you run the tests. There are 2 ways:

  • Using PAX EXAM, which will start an OSGi container and deploy your bundle there
  • Using CamelBlueprintTestSupport class as parent class of your tests, which will start a small embedded container just to run Camel

You can run tests with both JUnit or TestNG, the test framework is not relevant. Also note that PAX EXAM can run the exact JBoss Fuse version of your choice.

Using PAX EXAM

PAX EXAM runs the test by injecting a "probe bundle" inside the container. Imagine this probe bundle as a "copy" of the running test class. So in the test class you have full access to OSGi internals.
Then from the BundleContext you can ask OSGi for one of the services you registered.
This is a rough idea on how to get your auditPageNavDao bean:

@RunWith(PaxExam.class)
class YourTest {
    @javax.inject.Inject
    protected BundleContext bundleContext_;

    @Test
    testMethod() {

        ServiceReference<AuditPageNavDao> daoServiceReference_ = bundleContext_.getServiceReference(AuditPageNavDao.class);
        AuditPageNavDao dao = bundleContext_.getService(daoServiceReference_);
        // use DAO here

    }
}

Using CamelBlueprintTestSupport

You can easily interact with components and endpoints, like

MyBatisComponent mbc = context.getComponent("mydb", MyBatisComponent.class);
mbc.getSqlSessionFactory().openSession().getConnection();
// don't know if this will work
Object dao = context.getRegistry().lookupByName("auditPageNavDao");

I don't know how to get a Blueprint bean, probably CamelContext is a good starting point.

Upvotes: 2

Related Questions