aspose file tools*
The moose likes JDBC and the fly likes How to use JNDI to get a Pooled Connection Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Databases » JDBC
Bookmark "How to use JNDI to get a Pooled Connection" Watch "How to use JNDI to get a Pooled Connection" New topic
Author

How to use JNDI to get a Pooled Connection

Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
Hi !!

My aim is to get a simple pooled connection for my jdbc application through JNDI, so that in the JDBC source file, I dont have to hardcode anything (like username, password,etc....)

I am thinking of setting up the environment for jndi through application resource file (named jndi.properties) so that no parameters are in the source file. But I cant understand what to put in the jndi.properties file. Here is what I found on Sun's tutorial:

java.naming.factory.object=com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person
java.naming.factory.state=com.sun.jndi.ldap.CorbaToAttrs:com.wiz.from.Person
java.naming.factory.control=com.sun.jndi.ldap.ResponseControlFactory
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://localhost:389/o=jnditutorial
com.sun.jndi.ldap.netscape.schemaBugs=true


Here I cant understand what changes I have to make to make this work. I mean do I have to change "com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person" to something else. (I have no preference for underlying naming service right now). I am pretty sure I'll have to change "java.naming.provider.url=ldap://localhost:389/o=jnditutorial" to something else (seeing it has "jnditutorial" written at the end...)....but to what ??

I would be grateful if somebody could just tell me what I have to write in the jndi.properties file to make this work. I am connecting to SQL Server 2000.
By the way, below is the jdbc source file. (I am not sure if it is the right way to use jndi)





I really appreciate any help !!
Thank you in advance !!





Freddy Wong
Ranch Hand

Joined: Sep 11, 2006
Posts: 959

If you just simply want to avoid having to hardcode username, password, etc, why don't you use properties file?


SCJP 5.0, SCWCD 1.4, SCBCD 1.3, SCDJWS 1.4
My Blog
Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
Thanks for the reply Freddy !

Even if I simply use a properties file, I would still have to hardcode the Data Source (I am sorry, on reviewing my last post I realize I was not very clear on what all I didnt want to hardcode). So if the database is changed from SQLServer to Oracle I would have to make changes in source file, recompile, then redeploy it.....I am not sure because I am new to JNDI, but I think using JNDI can avoid this. Besides, I've been reading that getting the data source through JNDI is the best way due to many other reasons, and thats why I am a little bent on using JNDI...to get all the added advantages.

Also, how do i know if I have LDAP installed on my computer and it is running fine ? I did a "netstat -an" on command prompt and I didnt find LDAP written anywhere on the result. I thought it was installed along with jdk.


Also, on running the program, I get a ConnectException: Connection Refused.
I am now sure that the value for "java.naming.provider.url" is not right and I need to change it. But to what, I have no clue....what does "o=jnditutorial " mean anyways ?
Freddy Wong
Ranch Hand

Joined: Sep 11, 2006
Posts: 959

In that case, you can take a look at Apache Commons DBCP. That library allows you to create database connection pool that can be accessed through JNDI.

I have no clue....what does "o=jnditutorial " mean anyways ?

I hope you know understand the concept of LDAP. If not, you may want to read this and this. In summary, LDPA has this URL structure like this.
ldap://host:port/DN
the o=jnditutorial is the Distinguish Name (DN).

For comparisons between o and dc, read this.

Hope it helps.
Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
Thanks again Freddy ! Those links helped.

But do I have to know LDAP this much to use JNDI ? I know JNDI uses LDAP or something like that under the hood, but do I need to know much about it ? I simply abstracted myself away from these things and thought that JNDI "somehow" registers/binds names with objects (to "wherever"....but I know "wherever" is LDAP now) and I can lookup the name (which is bound to the required object) and get the object. Frankly, this is all I know about JNDI and LDAP conceptually. Is this enough ?

That library allows you to create database connection pool that can be accessed through JNDI.


I read about DBCP from the link you posted, and some other places, but i cant understand how using DBCP to get a pooled Connection will make getting that connection through JNDI easier (in terms of ease of getting datasource object through jndi how does it matter if i get pooled connection from DBCP or directly from the SQLServer driver's datasource imlpementation ?). Also, I dont know anything about servlets or the Tomcat server. (in case you assumed that I could use a servlet to get pooled connections from tomcat server...i read somewhere that using jndi that way would be much easier, as you only have to edit a context.xml and web.xml files....tomcat and servlet always pop up whenever I read about connection pooling or jndi or dbcp.....but unfortunetely I dont know anything about servlets,etc.) Give me a few more pointers please.
Thanks again !

Freddy Wong
Ranch Hand

Joined: Sep 11, 2006
Posts: 959

No, you don't need to know LDAP in order to understand JNDI. JNDI allows you to access directory services. LDAP is one example of directory services.

If your application is a web application, you can normally get the connection pool from the application server itself. But with standalone application, you normally need to create your own connection pool. DBCP can help you on that.


i cant understand how using DBCP to get a pooled Connection will make getting that connection through JNDI easier (in terms of ease of getting datasource object through jndi how does it matter if i get pooled connection from DBCP or directly from the SQLServer driver's datasource imlpementation ?).

I hope I get your question correctly. It all depends on how you prefer how the connection pool is being implemented whether it's by the DBCP or JDBC driver. I can't really comment on which one is better, though.

Hope that answers some of your questions.
Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
Oh ! Thanks ! Its good to know I dont need to know tomcat,etc. to use jndi in the simple way I want to.

I think my questions have been rather haphazard (I am confused), thats why I think you are not exactly able to know what I dont understand. I'll try to ask in a more organized manner this time, taking one problem at a time:

1. First step to use jndi has to be to register/bind a logical name with an object, right ? The object here is a datasource object. Say, I want to bind the logical name "jdbc/AcmeDB" to a datasource object. The following code should do it (taken from this site) (see under the heading "4.1.3 Creating and Registering a DataSource Object")




The above code gives an Exception because I havent set the environment settings. Now, I can either set the environment settings through a .properties file or directly in this code by making a Hashtable object, setting the values, and passing the Hashtable object in the InitialContext's constructor. Though using a .properties file would be better, lets just use a Hashtable here to make things simpler. Following code should do that (shouldn't it?):




Now, The Question is: What do I need to put in the place of "WHAT SHOULD I PUT HERE" 1 and 2 to make this code work ?
Also, are the values for Context.INITIAL_CONTEXT_FACTORY and Context.PROVIDER_URL right ?

Right now, no matter what I put in the place of "WHAT SHOULD I PUT HERE" 1 and 2, the above code gives the following Exceptions:

Exception in thread "main" javax.naming.CommunicationException: localhost:389 [Root exception is java.net.ConnectException: Connection refused: connect]
at com.sun.jndi.ldap.Connection.<init>(Connection.java:207)
at com.sun.jndi.ldap.LdapClient.<init>(LdapClient.java:118)
at com.sun.jndi.ldap.LdapClient.getInstance(LdapClient.java:1580)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2616)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:287)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.<init>(InitialContext.java:197)
at Register.main(Register.java:21)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
at java.net.Socket.connect(Socket.java:519)
at java.net.Socket.connect(Socket.java:469)
at java.net.Socket.<init>(Socket.java:366)
at java.net.Socket.<init>(Socket.java:180)
at com.sun.jndi.ldap.Connection.createSocket(Connection.java:349)
at com.sun.jndi.ldap.Connection.<init>(Connection.java:184)
... 13 more

I found the javadocs for these constants, and though they give me a good insight on what they are, I have no clue what to set their value to in my case. These are the javadocs :

Context.OBJECT_FACTORIES :
Constant that holds the name of the environment property for specifying the list of object factories to use. The value of the property should be a colon-separated list of the fully qualified class names of factory classes that will create an object given information about the object. This property may be specified in the environment, an applet parameter, a system property, or one or more resource files.
The value of this constant is "java.naming.factory.object".

Context.STATE_FACTORIES
Constant that holds the name of the environment property for specifying the list of state factories to use. The value of the property should be a colon-separated list of the fully qualified class names of state factory classes that will be used to get an object's state given the object itself. This property may be specified in the environment, an applet parameter, a system property, or one or more resource files.

I hope my question is clear this time.

Thanks a ton again Freddy !


Freddy Wong
Ranch Hand

Joined: Sep 11, 2006
Posts: 959

You need to understand that there are many JNDI providers. For simple purpose, you can use the filesystem service provider factory. You can download that JAR from this URL and download the File System Service Provider. Add that JAR in your classpath.

The code should be something like this.


Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
You need to understand that there are many JNDI providers. For simple purpose, you can use the filesystem service provider factory.


I was beginning to realize that after reading here and there, but that line nailed it in my head straightaway. Thanks !

I ran the code, and after that I could see the .bindings file in the directory. Which means the binding/registering part is done. Great !!

But when I ran the code to access it, there seems to be a problem. This is the code I ran:



This code gives the following Exception:

Exception in thread "main" javax.naming.NamingException: unexpected exception [Root exception is com.microsoft.sqlserver.jdbc.SQLServerException: Invalid DataSource reference.]; remaining name '"jdbc/AcmeDB"'
at com.sun.jndi.fscontext.FSContext.generateNamingException(FSContext.java:806)
at com.sun.jndi.fscontext.RefFSContext.lookup(RefFSContext.java:149)
at com.sun.jndi.fscontext.FSContext.lookup(FSContext.java:127)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at ConClass.main(ConClass.java:19)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Invalid DataSource reference.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:170)
at com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory.getObjectInstance(SQLServerDataSourceObjectFactory.java:37)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:304)
at com.sun.jndi.fscontext.RefFSContext.lookup(RefFSContext.java:146)
... 3 more
Java Result: 1
BUILD SUCCESSFUL (total time: 3 seconds)


Also, running the equivalent binding code (which runs alright) and then the code to access DataSource in case of MySQL database produces no Exception, but the DataSource reference is null. I tried it in MySQL thinking that maybe it'll work in it.

Googling the Exception is not helping at all. Also, I dont know if this is related, but when I started using hibernate I used to get some TCP/IP problem with SQLServer (the problem was not there with MySQL) and the usual solution to enable TCP/IP (from the enabled protocols in network configuration manager) did not help, and I have no firewall enabled too. I am not really concerned with that now (because I am not using Hibernate anymore), but I have written this because I thought that maybe the Exception is somehow related to that problem...


Thanks Again Freddy !!
Freddy Wong
Ranch Hand

Joined: Sep 11, 2006
Posts: 959

Actually the code that I gave you was meant for sample only and not the actual code. In actual code you probably need to pass in the username, password, driver name, and URL. I'm not very familiar with Microsoft SQL Server JDBC's driver, so I may not be much of a help.

Before you bind the object to JNDI, you need to add the some information into the Reference object. It's something like this (NOT the actual code).


Hope it helps.
Shitij Bhargava
Greenhorn

Joined: Jun 17, 2010
Posts: 10
Oh ! Ok. I was thinking that I would pass that information after I get the DataSource object....

How much of the code you posted in this last post is dependent on MS SQLServer driver ? I mean for the arguments to StringRefAddr(String type,String addrs) you give, do only the "addrs" depend on SQLServer driver or the argument "type" also ?

I know the SQLServer specific values for all the "addrs" arguments.
driver class name is: com.microsoft.sqlserver.jdbc.SQLServerDriver
The SQLServer JDBC URL is this: jdbc:sqlserver://ARUN32/FIREWALL_COPY_SHITIJ
And I know the username and password also. I definitely know these are right, because I am able to connect to SQLServer with these values (without JNDI) by usual methods like through a DataSource.
(But I CANT connect using DriverManager.getConnection() because of the same TCP/IP connection problem....so the only way to connect is to use a DataSource)

But unfortunately it still does not work. I tried the following code :



After reading this I also tried the following code: (seeing that there was no property named as "url" listed there.)



To clarify my question: If I plug-in the SQLServer specific values for "sql_server_driver_class_name" , "sql_server_jdbc_url", "user", "password" in the code you posted in the last post, should this work ? (But I have tried this, and it is not working....) OR the first argument you pass (the "type" arguments) are also SQLServer specific ? If yes (if the "type" arguments are also SQLServer specific) could you give me any idea where I can find those for SQLServer? or at least tell me what to search for on google (I dont exactly know what they are called, the link I posted above calls them "Properties" but the link is for building a connection string)?

Thanks a lot Freddy !!!

 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: How to use JNDI to get a Pooled Connection