How to make use of a DataSource via JNDI works? - java

there's some things I definitely don't understand while using JNDI.
This should simplify our Java developers' life, but this promise sounds false.
The simplest way tu use a database from within an application seems to build each time you need it (so, once per application) a datasource class giving you a connection or session you will use.
It's a tool class written in a few minutes where you have to declare the driver, url, login and password. And it's done.
The recommanded way is to rely on the server resources management, JNDI and all resources such as directory, etc.
But is it really usefull and simple ??
With Tomcat, you have to have to fully describe the datasource in server.xml, then declare it as a resource in context.xml.
server.xml
<GlobalNamingResources>
<Resource auth="Container" driverClassName="org.postgresql.Driver" maxIdle="30" maxTotal="100" maxWaitMillis="10000" name="jdbc/dsTriasEmployees" password="pwd" type="javax.sql.DataSource" url="jdbc:postgresql://localhost:5432/trias_employees" username="login"/>
</GlobalNamingResources>
context.xml
<ResourceLink name="jdbc/dsTriasEmployees" global="jdbc/dsTriasEmployees"
type="javax.sql.DataSource" />
Java side, you should be able to inject it thanks to a Context Lookup code ou a #Resource(mappedBy...) annotation.
DataSource datasource;
public Connection connectJNDI() {
try {
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
datasource = (DataSource) envContext.lookup("jdbc/trias_employees");
Connection con = datasource.getConnection();
genericLogger.info("JNDI LOOKUP -> " + con);
return con;
} catch (Exception ex) {
genericLogger.error("JNDI LOOKUP -> " + ex);
return null;
}
But after doing that, you still have to deal with error messages telling you that it's not enough just like this one :
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
I have read somewhere that I now should add a JNDI properties file and a declaration in the web.xml file like this :
web.xml
<resource-ref>
<description>
DB PostgreSQL
</description>
<res-ref-name>
jdbc/trias_employees
</res-ref-name>
<res-type>
javax.sql.DataSource
</res-type>
<res-auth>
Container
</res-auth>
</resource-ref>
But when I wanna test with jUnit, my web.xml is not usefull...
How many XML and properties files should I write just to respect the best practice that want me to delegate access to the datasource to the server ?
How many times will I have to duplicate all the informations related to url, pool connection, etc. ??
I've read 2 or 3 books on Java EE, 50 posts on StackOverFlow and dozens of forums and all the JNDI Resources HOW-TO on the Tomcat website.
But it still does not work...
Is there somewhere the full description of all I have to do to connect to my database using the JNDI process ?
Help me please, or I'll kill a kitten for each more minute I'm losing just to do my job in "the recommanded way".
Thanx by advance.

To test classes dependent on a DataSource or any other object provided by Tomcat via JNDI outside of Tomcat you could rely on TomcatJNDI. Point it to your server.xml and context.xml and it will initialize a JNDI environment with all the objects configured in the files.
TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processServerXml(serverXmlFile)
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();
Then lookup the datasource
DataSource ds = (DataSource) InitialContext.doLookup("java:comp/env/jdbc/trias_employee")
You can find out more about TomcatJNDI here.

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.

JDBC connection String in AWS Elastic Beanstalk

i want to migrate my applicaztion in aws,
i have setup my env. using elastic beanstalk.
in current version of my application, it runs OK locally, i setup the connection with this simple code:
in web.xml i have defined the resource:
<resource-ref>
<description> Resource reference to a factory for java.sql.Connection instances that may be used for talking to a particular database that is configured in the <Context> configuration for the web application. </description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
then in config.xml i defined the resource
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="utente1" password="utente1" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/nazioni?autoReconnect=true" />
now i'm able to get the connection in this way
/* JNDI query to locate the DataSource object */
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env") ;
// JNDI standard naming root
DataSource ds = (DataSource)envContext.lookup("jdbc/TestDB");
/* Ask DataSource for a connection */
Connection conn = ds.getConnection();
now my question is: can i hard code the connection string in my config.xml or it is better to use System.getProperty("JDBC_CONNECTION_STRING")? if so, how i can set the connection string when tomcat is loaded ?
thanks, Loris
Tomcat Configuration Reference mentioning support for Ant-style variable substitution:
Apache Ant-style variable substitution is supported; a system property
with the name propname may be used in a configuration file using the
syntax ${propname}. All system properties are available including
those set using the -D syntax, those automatically made available by
the JVM and those configured in the
$CATALINA_BASE/conf/catalina.properties file.
It means that if you define a property within .ebextensions/<environment-name>.config such as:
option_settings:
- option_name: JDBC_CONNECTION_STRING
value: jdbc:mysql://localhost:3306/nazioni?autoReconnect=true
Then you should be able to reference that property in the configuration files:
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="utente1" password="utente1" driverClassName="com.mysql.jdbc.Driver" url="{JDBC_CONNECTION_STRING}" />
The approach has at least two benefits over hardcoded:
The value can be changed manually in AWS Beanstalk Console on a running instance
The value can be changed programmatically on a running instance
Better go with XML configuration Becasue most of the application when moved from one Environment to another.There will be change in XML probably so XML is better from my Experience.
Also you can use property file but which helps most of the time when you want some property which is to be changed very often like lables not like configuration based things DB Connection String,SMTP,etc.
The Name of WEB.XML is Deployment descriptor becasue at the time deployment which is useful to load details about Applications based on the different environment.
In general, it is best NOT to hard-code connection string information within your application (or other similar application configuration). Ideally you want to externalize application configuration so that your application to be portable between environments.
In the case of Elastic Beanstalk, you could deploy the same application WAR in different Beanstalk environments at the same time (perhaps a QA and a PROD environment) and if you hard-code the connection string then both WAR files would be pointing to the same DB instance.
Similarly, you may need to change the connection string at some point, maybe because your DB instance name changed, and if you hard-code the connection string then you would have to rebuild and deploy a new JAR.
If you use the JDBC_CONNECTION_STRING configuration provided by Elastic Beanstalk and read these in at runtime, then you can easily change the connection string using the Elastic Beanstalk console or API, and you can also maintain portability for a single WAR between different environments.

Lookup a JDBC DataSource in WebSphere 8.5

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" />

How to lookup a (JDBC) JNDI resource?

We have a personal java library which is deployed on a tomcat server (v5.5 & v6).
This library is shared with many web applications, so it was deployed on shared/lib in tomcat directory.
Exceptionaly, i have to create a new class into this library which lookup a jdbc datasource via JNDI.
For that, here my code :
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
DataSource dataSource = (DataSource) envCtx.lookup("jdbc/corp.xx.xx.xxxxDS");
All context are instantiated without problem. But when it lookup the jdbc datasource, i have an exception : Name jdbc not Found in Context
We are not in a webapp, is it a problem ?
Is it possible to declare a context.xml with a ResourceLink ? how ?
nb: the jndi is setted in server.xml (a resource in GlobalNamingResources)
<Context ...>
...
<ResourceLink name="linkToGlobalResource"
global="simpleValue"
type="java.lang.Integer"
...
</Context>
Where name is the new name (name relative to java:comp/env), global is the global jndi name configured in server.xml
So, from your code, look up linkToGlobalResource which will give you the linked global resource
Reference: http://tomcat.apache.org/tomcat-5.5-doc/config/context.html#Resource_Links
Answer Updated:
Your JNDI access will be from web-app and not shared jar because standalone jar does not have the concept of context.

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