Search code examples
javaosgiwebsphere-libertyosgi-bundleopen-liberty

OpenLiberty custom feature dataSource


I'd like my custom OSGi Liberty feature to inject/lookup JNDI datasource, the one that is already defined 'as usual'. Something like this:

<server description="my-server">

<!-- I prefer this, not being forced to define url, driver, username and password here as well -->
<myJdbcRegistry dataSourceJndiName="jdbc/myDataSource" />

<!-- This dataSource exists anyway, i do not want to repeat all attributes that are inside properties.oracle -->
<dataSource id="my-dataSource" connectionManagerRef="connection-manager" jndiName="jdbc/myDataSource" transactional="true" type="javax.sql.DataSource"> 
    <jdbcDriver libraryRef="oracle-ojdbc8-library"/> 
    <properties.oracle URL="${my.db.url}" driverType="thin" password="{xor}${my.db.password}" user="${my.db.user}"/> 
</dataSource>

<library id="oracle-ojdbc8-library"> 
    <fileset dir="${shared.resource.dir}/jdbc" includes="ojdbc8-19.7.0.0.jar"/> 
</library>

Is this even possible to do? I tried several approaches without results (different InitialContext lookups, OSGi BundleContext#createFilter, BundleContext#getServiceReferences).


Solution

  • Yes, it's possible, but there is some complexity to it. The dataSource element isn't actually a DataSource. It's a ResourceFactory for creating a data source based on a resource reference. In Liberty, configuration usually references other configuration by its id, so more typical configuration that follows conventions of other config elements would look like this:

    <myJdbcRegistry dataSourceRef="my-dataSource"/>
    

    Here's an example from Liberty code itself where another configuration element requires a dataSource and references it by id,

    Metatype:

      <AD id="dataSourceRef"                     type="String"  default="DefaultDataSource" ibm:type="pid" ibm:reference="com.ibm.ws.jdbc.dataSource" name="%dataSource" description="%dataSoure.desc"/>
      <AD id="DataSourceFactory.target"          type="String"  default="(service.pid=${dataSourceRef})" ibm:final="true" name="internal" description="internal use only"/>
    

    OSGI bind method:

        @Reference(target = "(id=unbound)")
        protected void setDataSourceFactory(ResourceFactory svc) {
    

    Usage:

            ResourceConfig resourceInfo = resourceConfigFactory.createResourceConfig(DataSource.class.getName());
            resourceInfo.setSharingScope(ResourceConfig.SHARING_SCOPE_SHAREABLE);
            resourceInfo.setIsolationLevel(isolationLevel);
            resourceInfo.setResAuthType(ResourceConfig.AUTH_CONTAINER);
            ...
            DataSource dataSource = (DataSource) dataSourceFactory.createResource(resourceInfo);