Developing with the JNDI default namespace in a Liberty feature

You can make an object available in the default Java™ Naming and Directory Interface (JNDI) namespace. To do that, you must register it in the OSGi service registry with the osgi.jndi.service.name service property. The value of osgi.jndi.service.name is the required JNDI name. Similarly, to find an object in the default JNDI namespace, you can search the OSGi service registry with the osgi.jndi.service.name service property. The value of osgi.jndi.service.name is the JNDI name.

About this task

Compared with explicitly calling Context.bind or Context.lookup, using the service registry has the following benefits:
  • Your feature works properly when jndi-1.0 is enabled, but your feature does not need an explicit dependency on JNDI.
  • You do not need to explicitly unbind objects from JNDI when your feature is removed because the OSGi framework automatically unregisters services when bundles are stopped.
  • You can easily implement lazy initialization using declarative services or ServiceFactory rather than using Reference and ObjectFactory.

For more information about JNDI, see Naming.

Procedure

  1. Register a service using the osgi.jndi.service.name property with the JNDI name.
    For more information about registering services, see Registering OSGi services.
  2. Update your metatype.xml to allow a JNDI name to be specified in server configuration.
    To allow users to specify a JNDI name for your service, use the jndiName id for consistency with other features in the Liberty run time, for example:
    <AD id="jndiName" name="JNDI name" description="JNDI name for a widget." type="String" ibm:unique="jndiName"/>
    You can use an internal attribute to automatically set the osgi.jndi.service.name service property with the value of the jndiName attribute, for example:
    <AD id="osgi.jndi.service.name" name="internal" description="internal" type="String" default="${jndiName}"/>
    For more information about OSGi Metatype, see Advanced Configuration.
  3. Implement the ResourceFactory interface if you need Java EE resource reference information.
    If your service needs Java EE resource reference information, such as res-auth, you can register a ResourceFactory in the OSGi service registry with the jndiName and creates.objectClass properties. The ResourceFactory service is re-registered automatically with the osgi.jndi.service.name property.
    For example:
        import com.ibm.wsspi.resource.ResourceFactory;
        public class WidgetResourceFactory implements ResourceFactory { ... }
    
        Properties properties = new Properties();
        properties.put(ResourceFactory.JNDI_NAME, "widget/abc");
        properties.put(ResourceFactory.CREATES_OBJECT_CLASS, Widget.class.getName());
        bundleContext.registerService(ResourceFactory.class, new WidgetResourceFactory(), properties);
    Alternatively, the service could be registered automatically using declarative services and metatype. In that case, you can specify the creates.objectClass property as a declarative services property. You do not need to specify the jndiName property because it is set automatically from the user configuration with the <AD id="jndiName"> element in the metatype.xml file in step 2, and you do not need an <AD id="osgi.jndi.service.name> element in the metatype.xml file because the ResourceFactory service will be re-registered automatically.
  4. Locate an object using the osgi.jndi.service.name property with the JNDI name.
    For example:
    bundleContext.getServiceReference(DataSource.class, "(osgi.jndi.service.name=jdbc/myds)");
    Alternatively, you can locate a ResourceFactory using the jndiName and creates.objectClass properties.
  5. Update your metatype.xml to allow a resource to be specified in server.xml using the id of the resource. This allows the resource to be accessed regardless of whether or not the resource has a jndiName.
    For example,
    <AD id="dataSourceRef" type="String" ibm:type="pid" ibm:reference="com.ibm.ws.jdbc.dataSource"
     cardinality="1" name="%dataSourceRef" description="%dataSourceRef.desc"/>
    If you are using declarative services, you can use an internal attribute to set a .target service property with a filter. For example, if your declarative services component has a reference named dataSource, you can use the following attribute definition to ensure that the dataSource that is referenced by the dataSourceRef configuration attribute is used.
    <AD id="dataSource.target" type="String" default="(service.pid=${dataSourceRef})" ibm:final="true" name="internal" description="internal"/>