Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I connect to a Websphere Datasource with a given JNDI name?

I'm using Websphere Portal 7.0 and creating a portlet with RAD 8.0. My portlet is trying to make a db2 connection to a remote server. I wrote a java program locally to do a basic JDBC connection to the server and get records from a table. The code works fine; however, when I add the code to my portlet as well as the db2jcc4.jar, the connection doesn't work. I'm using the basic:

Connection connection = DriverManager.getConnection("jdbc:db2://server:port/db:user=user;password=pw;");

I figure that using the Websphere datasource is the right way to go. I know the JNDI name for the datasource, but I'm not finding clear cut examples on how to make a connection. Several examples use a DataSource class (I typed this in and this doesn't seem like it comes from a native java package so what import do I use here?) coupled with a Context. I've come across code like:

Context ctx = new InitialContext();
ctx.lookup("jdbc/xxxx");

... Can someone break this down for me?

EDIT 1

I've updated my code per the answers listed. I really think I'm getting closer. Here is my getConnection() method:

private Connection getConnection() throws SQLException {
    javax.naming.InitialContext ctx = null;
    javax.sql.DataSource ds = null;
    System.out.println("Attempting connection..." + DateUtil.now() );
    try {
        ctx = new javax.naming.InitialContext();
        ds = (javax.sql.DataSource) ctx.lookup("java:comp/env/jdbc/db");
        connection = ds.getConnection();
    } catch (NamingException e) {
        System.out.println("peformanceappraisalstatus: COULDN'T CREATE CONNECTION!");
        e.printStackTrace();
    }       
    System.out.println("connection: " + connection.getClass().getName() + " at " + DateUtil.now());
    return connection;
}

My entire web.xml file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>PeformanceAppraisalStatus</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    <resource-ref>
        <description>
        Datasource connection to Db</description>
        <res-ref-name>jdbc/db</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
</web-app>

I am seeing an error that describes the very thing you guys are telling me Websphere should prompt me to do, but doesn't:

SRVE0169I: Loading Web Module: PeformanceAppraisalStatus.
[8/23/11 18:08:02:166 CDT] 00000009 InjectionProc E   CWNEN0044E: A resource reference binding could not be found for the jdbc/db resource reference, defined for the PeformanceAppraisalStatus component.
[8/23/11 18:08:02:169 CDT] 00000009 InjectionEngi E   CWNEN0011E:  The injection engine failed to process bindings for the metadata.

Yes, I know that I've mispelled performance as peformance throughout the app.

SOLUTION

I was so very close. Here are the missing bits that made it all fall into place:

web.xml:
<resource-ref>      
    <description>
    Datasource connection to db</description>
    <res-ref-name>jdbc/db</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
    <mapped-name>jdbc/db</mapped-name>      
</resource-ref>

ibm-web-bnd.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd 
    xmlns="http://websphere.ibm.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_0.xsd"
    version="1.0">

    <virtual-host name="default_host" />


    <resource-ref name="jdbc/db" binding-name="jdbc/mydatasource" />
</web-bnd>

It appears that the ibm-web-bnd.xml file handles the binding between the project resource name and the datasource in websphere. Once I added the line:

<resource-ref name="jdbc/db" binding-name="jdbc/mydatasource" />

Websphere Portal seemed appeased. My code is working and connecting to the database now.

like image 248
jason Avatar asked Aug 23 '11 20:08

jason


People also ask

How can I get JNDI name for DataSource?

To obtain a reference to a data source bound to the JNDI context, look up the data source's JNDI name from the initial context object. The object retrieved in this way is cast as a DataSource type object: ds = (DataSource)ctx. lookup(JndiDataSourceName);

What is JNDI name in WebSphere?

When you create a WebSphere Application Server data source, the default JNDI name is set to jdbc/data_source_name . When you create a connection factory, its default name is eis/j2c_connection_factory_name .

Where is JNDI in WebSphere?

To Determine the JNDI Port to Specify In the WebSphere administration console, navigate to Servers > Application Servers > Your_Server > Ports. Look at the BOOTSTRAP_ADDRESS property. Use the specified port in the java. naming.

What does JNDI lookup () method do?

Basic lookup JNDI (Java Naming and Directory Interface) organizes its names into a hierarchy. A name can be any string such as "com. example.


3 Answers

You need to define a resource reference in your application and then map that logical resource reference to the physical resource (data source) during deployment.

In your web.xml, add the following configuration (modifying the names and properties as appropriate):

<resource-ref>
    <description>Resource reference to my database</description>
    <res-ref-name>jdbc/MyDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Then, during application deployment, WAS will prompt you to map this resource reference (jdbc/MyDB) to the data source you created in WAS.

In your code, you can obtain the DataSource similar to how you've shown it in your example; however, the JNDI name you'll use to look it up should actually be the resource reference's name you defined (res-ref-name), rather than the JNDI name of the physical data source. Also, you'll need to prefix the res-ref-name with the application naming context (java:comp/env/).

Context ctx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDB");
like image 60
shelley Avatar answered Oct 31 '22 18:10

shelley


To get a connection from a data source, the following code should work:

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

Context ctx = new InitialContext();
DataSource dataSource = ctx.lookup("java:comp/env/jdbc/xxxx");
Connection conn = dataSource.getConnection();

// use the connection

conn.close();

While you can look up a data source as defined in the Websphere Data Sources config (i.e. through the websphere console) directly, the lookup from java:comp/env/jdbc/xxxx means that there needs to be an entry in web.xml:

<resource-ref>
    <res-ref-name>jdbc/xxxx</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

This means that data sources can be mapped on a per application bases and you don't need to change the name of the data source if you want to point your app to a different data source. This is useful when deploying the application to different servers (e.g. test, preprod, prod) which need to point to different databases.

like image 24
beny23 Avatar answered Oct 31 '22 17:10

beny23


DNS for Services

JNDI needs to be approached with the understanding that it is a service locator. When the desired service is hosted on the same server/node as the application, then your use of InitialContext may work.

What makes it more complicated is that defining a Data Source in Web Sphere (at least back in 4.0) allowed you to define the visibility to various degrees. Basically it adds namespaces to the environment and clients have to know where the resource is hosted.

Simple example.

javax.naming.InitialContext ctx = new javax.naming.InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/DataSourceAlias");

Here is IBM's reference page.

If you are trying to reference a data source from an app that is NOT in the J2EE container, you'll need a slightly different approach starting with needing some J2EE client jars in your classpath. http://www.coderanch.com/t/75386/Websphere/lookup-datasources-JNDI-outside-EE

like image 25
Kelly S. French Avatar answered Oct 31 '22 18:10

Kelly S. French