Search code examples
javaapache-camelosgiblueprint-osgi

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
    {
    }

}

Solution

  • 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.