Lookup a JDBC DataSource in WebSphere 8.5 - java

I want to use a JDBC Connetion in my webapp which is configured in WebSphere. (Like this one here: How to use JDBC in JavaEE?)
I had used this DataSource before via JPA but our customer wants to have native SQL ... don't ask.
I found a lot of examples and tutorial (e.g. http://www.wickcentral.com/java/dl/ds_resreferencesetts_Websphere.pdf, Websphere JNDI lookup fails) but nothing want work.
The DataSource in the WebSphere has the JNDI-Name "jdbc/myDS"
I added a resource-ref to my web.xml:
<resource-ref>
<res-ref-name>jdbc/myDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
And I tryed to get the DataSource in my Dao:
ds = (DataSource) new InitialContext()
.lookup("java:comp/env/jdbc/myDS");
But what I get is a
com.ibm.wsspi.injectionengine.InjectionException: CWNEN0044E: A resource reference binding could not be found for the following resource references [jdbc/myDS], defined for the MyAPP component.
I tryed a lot. Did anyone sees the fault?

Did you match your web-app defined datasource with a Websphere defined datasource during installation? Websphere usually asks you to bind resources when they are detected on the installation process (If I remember correctly, it is in the step named "Map reference resources to resources").
Other common issue is a Websphere datasource in a different context (Cell/Node/Server) than your app, so it cannot be found at runtime.

You need to add the binding in ibm-web-bnd.xml:
<resource-ref name="jdbc/myDS" binding-name="jdbc/myDS" />

Related

javax.naming.NameNotFoundException: on WebSphere Liberty

I'm trying to use a datasource configurated as a JNDI on a WebSphere Application Server Liberty however I'm getting the follwoing error:
javax.naming.NameNotFoundException: java:comp/env/jdbc/myapp/master
The configuration for the datasource in Websphere application server is:
<dataSource commitOrRollbackOnCleanup="commit" id="jdbc/myapp/master" jdbcDriverRef="ojdbc7" jndiName="jdbc/myapp/master">
<properties.oracle URL="jdbc:oracle:thin:#127.0.0.1:1521:xe" oracleRACXARecoveryDelay="0" password="xxxxxxxx" user="app_master">
</properties.oracle>
<connectionManager maxPoolSize="50"/>
</dataSource>
The connection to database is made via this code inside a servlet (jndi=jdbc/myapp/master):
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup(jndi);
setConnection(ds.getConnection());
System.out.println(getConnection().toString() );
What am I doing wrong?
The java:comp/env requires resource reference. You have following options to solve that:
1) Use resource injection - so instead of looking up it directly (via InitialContext) just add the following in your servlet class
#Resource(lookup = "jdbc/myapp/master", name="jdbc/myapp/master")
private DataSource dataSource;
2) Define resource reference in your web.xml like
<resource-ref>
<description>my datasource</description>
<res-ref-name>jdbc/myapp/master</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>CONTAINER</res-auth>
</resource-ref>
or you can create just reference also via annotation in the code.
3) Use direct JNDI, without reference (not a Java EE best practice)
DataSource ds = (DataSource) initCtx.lookup("jdbc/myapp/master");
In addition to what is already stated in the other answer, you should also check that you have enabled the jndi-1.0 feature. This is a common cause of lookups not working in Liberty.
For example, in server.xml,
<featureManager>
<feature>jdbc-4.2</feature>
<feature>jndi-1.0</feature>
... other features that you use
</featureManager>
And if this, too, is not enough to get it working, you should also check the configuration of resources upon which the dataSource depends, such as the jdbcDriver with id of ojdbc7 which is referenced in the config snippet that you provided.

Websphere change JNDI name in EAR

I got a legacy EJB 2 application which I deploy to Websphere 8.5. The application has dependencies, which define JNDI bindings to a DataSource in /META-INF/ejb-jar.xml and /META-INF/ibm-ejb-jar-bnd.xml.
I'm not allowed to change the code in those dependencies and neither can I change the Websphere's config. But I could make changes to the config files in the jar files.
I want to override the effective JNDI bindings in my application. Is it possible to define a file that will be added to the Ear to override those bindings?
snippet of the ejb-jar.xml:
<resource-ref id="ResourceRef_1248968390265">
<res-ref-name>jdbc/CentralDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
ibm-ejb-jar-bnd.xml:
<session name="FooJob">
<resource-ref name="jdbc/CentralDS" binding-name="jdbc/VeryCentralDs" />
</session>
Is it possible to override this JNDI name (VeryCentralDs) somewhere?
Yes, it is possible to override resource reference bindings at deployment time. This knowledge center article steps through deploying an application. Watch for the step "Map resource references to resources" which is documented here. This is where you can fill in the target JNDI name that you want the resource reference bound to.

is res-type required for JNDI setup in web.xml?

I met the situation that JNDI provider on different application servers might have different proxy interface/class(like in JMS, Websphere may have javax.jms.QueueConnectionFactory instead of javax.jms.ConnectionFactory), so in web.xml
<resource-ref>
<description>JNDI for jms access</description>
<res-ref-name>jms/ConnectionFactory</res-ref-name>
<res-type>javax.jms.QueueConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Is the <res-type>javax.sql.DataSource</res-type> must defined to make everything works?
I think the JNDI name should be fine as it should be unique in the initial context?
I do find something from Oracle but not sure it is official?
From the EE platform spec (emphasis mine):
The res-type element is optional if an injection target is specified
for this resource; in this case the res-type defaults to the type of
the injection target.
I believe javax.jms.ConnectionFactory should also work on WebSphere Application Server if some other application server requires a different value.

Explanation of context.xml

When using Tomcat, I've always treated web.xml as a kind of .htaccess or httpd.conf equivalent. It seems natural that there might have to be some way of configuring a web server.
However, I don't quite understand the purpose of context.xml. For instance, when working with JDBC, why do I have to add a resource-ref in web.xml and also a Resource with even more info in context.xml? Could I eliminate the context.xml file and somehow instantiate the DataSource in my code? I am asking because hypothetical examples like that help me understand.
EDIT: I am trying to understand what is happening in configs like this, in /META-INF/context.xml:
<Context>
<Resource name="jdbc/postgres" auth="Container" type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver" url="jdbc:postgresql://127.0.0.1:5432"
username="postgres" password="yes" maxActive="20" maxIdle="10"
maxWait="-1" />
</Context>
and, in WEB-INF/web.xml:
<resource-ref>
<description>postgreSQL Datasource example</description>
<res-ref-name>jdbc/postgres</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Why do I have to put both of those in there to use JDBC? What are they doing exactly and is there another way of doing the same thing but in the Java code? Like I said, not because I want to, but because I want to understand what they are doing better.
I don't quite understand the purpose of context.xml
context.xml is called from the web.xml through <context-param> tag. As you web.xml loads first when an application is created and it will create the references for the contexts that are configured in it.
I don't quite understand the purpose of context.xml
So, the purpose of context.xml is adding separation of codes. you can have separate contexts for different purposes . for example For Database connectivity, using other frameworks etc..,
Could I eliminate the context.xml file and somehow instantiate the DataSource in my code?
Yes ,you can do that by configuring the datasource in web.xml itself.
Hope this helps !!
To your initial questions:
I don't quite understand the purpose of context.xml
In Tomcat, you'll frequently see the term "Context". When you see this it's just referring to your application (i.e. Context == your web app). Thus /META-INF/context.xml is the configuration file specific to your application (actually, it's one of the configuration files because there are others).
For instance, when working with JDBC, why do I have to add a resource-ref in web.xml and also a Resource with even more info in context.xml?
You don't. You do not need to add anything to web.xml. If you define the resource in /META-INF/context.xml, Tomcat will create your resource and expose it through JNDI. You can then retrieve it as you would any resource from JNDI.
Could I eliminate the context.xml file and somehow instantiate the DataSource in my code?
Possibly. It's common to see Spring users create a DataSource in their Spring bean definitions. If you're not using Spring, you could still do it, but it would be more work.
Regardless of how you do this, if you setup the DataSource in your application you lose some flexibility. For example, you cannot share the DataSource across multiple applications and your application has to know how to set up the DataSource. If you define the DataSource in the server's configuration (i.e. with a Resource tag) then your application does not need this information.
To the response by san krish:
So, the purpose of context.xml is adding separation of codes. you can have separate contexts for different purposes . for example For Database connectivity, using other frameworks etc..,
The purpose of the Context tag is to configure the context (i.e. your application). It might provide you with the ability to pull certain aspects of your application, like the DataSource, out of the code and into configuration, but that's just the benefit of externalizing your configuration. It's not the purpose of this file.
Yes ,you can do that by configuring the datasource in web.xml itself.
No, with Tomcat you cannot configure a DataSource strictly through web.xml. It's just not possible to provide all of the information in web.xml that is required to create a DataSource. Because of this, you need to define a Resource tag for your DataSource and it is redundant to specify your DataSource in web.xml.

How to map a datasource for a java web service

I'm trying to figure out how to use datasources for my web service. I have the oracle-ds.xml deployed on my jboss 4.2.3 server, and the datasources are showing as bounded to JNDI names java:TestDS, java:WeatherDS, etc.
I try doing an initialcontext.lookup but I can't find it. I tried referencing the resource in the web.xml but I get "java:WeatherDS has no valid JNDI binding"... I've tried referencing "java:/WeatherDS", "WeatherDS", "java:WeatherDS", "jdbc/WeatherDS" and some others, but I think I need to somehow map the reference name to the jndi name.
I found a snippet of code that says:
...
<resource-ref>
<res-ref-name>jdbc/DefaultDS</res-ref-name>
<jndi-name>java:/DefaultDS</jndi-name>
</resource-ref>
...
But, it doesn't say where this file is and what else is needed. I don't know if I need a resource reference for sure or not. Can anyone point me in the direction of some more complete information of how to access the datasource from the code once it has been deployed? I am trying to make it so the connections are pooled for my web service.
In JBoss-4.2.3 you define a datasource in an XML-File in folder [JBOSS_HOME]/server/[MYSERVER]/deploy/
Create a file in this folder with name: mydatasource-ds.xml.
XML-File content:
<datasources>
<local-tx-datasource>
<jndi-name>mydatasource</jndi-name>
<!-- Properties for SQLServer -->
<connection-url>jdbc:jtds:sqlserver://hostname:1433/db-name;TDS=8.0;lastUpdateCount=true;sendStringParametersAsUnicode=false</connection-url>
<driver-class>net.sourceforge.jtds.jdbc.Driver</driver-class>
<!-- Properties for SQLServer end -->
<user-name>name</user-name>
<password>pwd</password>
<min-pool-size>5</min-pool-size>
<max-pool-size>50</max-pool-size>
<idle-timeout-minutes>15</idle-timeout-minutes>
<blocking-timeout-millis>15000</blocking-timeout-millis>
</local-tx-datasource>
</datasources>
To can access these datasource from every application deployed in the same JBoss by normal JNDI lookup.
IMPORTANT: Use prefix java:/ in the jndi name in your code. Full JNDI-Name in your application for the datasource above is java:/mydatasource

Categories

Resources