I am implementing JNDI concept to get a connection to Database. I googled to get the starting point, however didn't get it.
The things that i want to do is have a simple java standalone application which used JNDI concept for getting connected to a database.
Sample source that i have is:
DataSource dataSource = null;
Context context = null;
try {
context = new InitialContext();
dataSource = (DataSource) context.lookup("database_connection");
}
catch (NamingException e) {
System.out.println("Got naming exception, details are -> " + e.getMessage());
}
Now, where we define database_connection? Is that defined in an xml file, and if so where do we specify that and what format of that is?
If any pointers can be provided, that would be great.
Thanks
The real difference between your question and the examples is that you're using a standalone Java application. Pretty-much every example assumes that you're running within a Java EE application container. In that case you define the database connection to the container, use JNDI to get the DataSource, and get the connection from that.
When you do a JNDI lookup to get your DataSource, the JNDI framework looks for an initial context factory (a class that implements InitialContextFactory). In your Java EE application, the container provides that. In your standalone Java application, the initial context is null, and no further lookups resolve correctly.
One of the ways you can resolve this is to create your own initial context factory:
public class MyContextFactory implements InitialContextFactory
and inject that into JNDI at startup:
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "mypackag.MyContextFactory");
and then return a new ObjectFactory from the getInitialContext call, and then implement the ObjectFactory to return a DataSource (also probably custom) from the getConnection() call.
That would all work, but it's overkill. It would be easier to just use the normal JDBC connection string approach to get a connection directly in your application rather than trying to use a DataSource. Or use a framework like Spring to inject it for you or to separate the database connect information from the code (in which case you're using Spring configuration files rather than JNDI directly).
The one reason I'd advocate creating a custom context factory and data source approach is if you have common JPA code that you want to run both within a Java EE app and within a standalone app (it's otherwise non-trivial to configure the same code to do both). That doesn't sound like your case.
So, since you're standalone and not in a Java EE container, I think your real answer is that your use case is not appropriate for a DataSource (unless you move to a framework like Spring that would provide one).
There's a nice tutorial for that here and here
The database should be defined somewhere (LDAP)? There's a series of old articles using the directory service with JNDI (ultimately in your case to get the server information) here.
A nice introduction to naming services here
Related
In a java application, If we want to use javax.sql.DataSource instead of java.sql.DriverManager to get connections, which approach would be better to create DataSource and WHY?
Create DataSource in the application itself at the application startup time
or
Configure DataSource in the application server and get it via JNDI
Well, it actually depends upon the requirement. You can take this as a general rule.If you have multiple applications and sharing the same DataSource, then it can be a good choice to configure the DataSource in the server. Otherwise, if this is the only application uses the DataSource, then you can have it in the application level itself.
I'm developing a web application with Java and it needs a connection with a data base. Well administration of resources is very important. The application will be in a Tomcat 6 servlet container, and I've implemented BoneCP to manage connections (I can't use Spring).
I've read that JNDI lookup for DataSource is too much expensive and I'm thinking about creating a singleton of DataSource object, to get the JNDI resource only once, and return the same DataSource for future connections.
Question: Is it a good idea to create a DataSource only once, and get connections from the same DataSource? I don't want to get the same connection, only the same DataSource.
Thank you ;)
Use a pooling datasource, such as is described here:
http://www.javaranch.com/journal/200601/JDBCConnectionPooling.html
Yes, as Renjith suggested, you only need to create the DataSource one time. I actually ran into this same issue yesterday. Every time in my "getConnection" method I noticed I was creating a new InitialContext and DataSource unnecessarily. I revised my Connection Manager class to have a static block of code that creates the DataSource object only when the class gets loaded the first time (after reading BalusC's answer in Proper usage of JDBC Connection Pool (Glassfish))
I thought about using the old-school ServiceLocator pattern (see Pascal's answer in the above link), but I felt it was a bit too overkill for my needs.
Another possibility is that you could also use the #Resource annotation with injection on the DataSources, but that doesn't seem to work with Tomcat 7.
My WAR application is deployed to Amazon Elastic Beanstalk. They don't support JNDI, but I need it for JPA and unit tests. What JNDI context factory I can use as a workaround? I need a simple open source solution, that would allow me to configure entire factory through jndi.properties. I tried GuiceyFruit, but looks like it doesn't allow data source configuration inside one file. Any suggestions?
ps. OpenEJB will work, but it's an overkill for such a simple task
Try Simple-JNDI. It gives you an in-memory implementation of a JNDI Service and allows you to populate the JNDI environment with objects defined in property files. There is also support for loading datasources or connection pools configured in a file.
To get a connection pool you have to create a file like this:
type=javax.sql.DataSource
driver=com.sybase.jdbc3.jdbc.SybDriver
pool=myDataSource
url=jdbc:sybase:Tds:servername:5000
user=user
password=password
In your application you can access the pool via
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("path/to/your/connectionPool");
You can find more about it at https://github.com/h-thurow/Simple-JNDI.
I have a .properties file in my application which contains dataSource properties.
I set up a JNDI reference to this dataSource using the following code :
// first I create MyDataSource from the properties found in the .properties file
//then :
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind(jdbc/oracle/myDataSource, MyDataSource);
If I use a lookup in this application, the dataSource is found :
Context initContext = new InitialContext();
BasicDataSource dataSource =
(BasicDataSource) initContext.lookup("jdbc/oracle/myDataSource")
//everything works fine and I can use my dataSource to getConnection,
//requests, etc...
Now I would like to use this dataSource in another application. But if I do the same lookup than previously, I don't find myDataSource (whereas there is still the previous application in tomcat and the jndi binding is done on start-up with the help of a listener).
How can I get myDataSource in this second application, given that I can't use a Tomcat's resource in server.xml or a context.xml file (for different reasons I have to use this .properties file)?
Thanks
"local" JDNI directories are read-only in Tomcat. Nevertheless, you can bind "global" JNDI resources in a LifecycleListener, and then "link" them to your context(s)(*):
You need to implement org.apache.catalina.LifecycleListener http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/LifecycleListener.html
Then register it in your server.xml like this (along with the other listeners):
<Listener className="yourlistener.YourLifecycleListener"/>
Your listener should await for 2 events:
public void lifecycleEvent(final LifecycleEvent event) {
if (Lifecycle.START_EVENT.equals(event.getType())) {
// Create your datasource instance...
Context initContext = new InitialContext();
initContext.createSubcontext("jdbc");
initContext.createSubcontext("jdbc/oracle");
initContext.rebind("jdbc/oracle/myDataSource", myDataSource);
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
// unbind...
}
}
Then you'll have to propagate resource accesses by "linking" them from "global" JNDI directory to "local" JNDI directory using ResourceLink element in your META-INF/context.xml:
<ResourceLink name="jdbc/oracle/myDataSource" global="jdbc/oracle/myDataSource"
type="javax.sql.DataSource" />
That worked for me so far.
(*) Some notes:
There's an advantage on using lifecycle listeners. Since the order of context creation is not guaranteed. The advantage is that all of your contexts will see this object created.
If you need to create and configure datasource creation more dynamically that on lifecycle listener creation, note that you can bind a custom class implementing the Factory pattern.
To avoid classloading incompatibility problems, consider putting your listener, datasource, etc. classes in a jar file in the Tomcat lib directory, so they're included y the common classloader.
Regards.
What you are trying to do is not going to work. J2EE applications are not allowed to modify the JNDI environment provided by the application server (J2EE spec, section 5.2.2) and the Tomcat JNDI documentation also states, that each web applications gets each own read-only JNDI environment. I'm not sure why binding/rebinding your datasource is not failing immediately and why it's working within the same web application, but even such application-internal usage of the JNDI environment is undocumented behaviour, which I would not rely on.
A couple people have already commented on this, but I think the answer to your question is: Tomcat has a file called server.xml that you need to use. A good reference I have used before is below:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-resources-howto.html
Resources defined here will be visible to all apps deployed (if set up correctly). If you set up a JNDI resource in your apps context or web xml file, it should only be available to your app.
JNDI context are private to each webapp. Context created in one app can't be accessed by others.
Try to create an entry in GlobalNamingResources and links in both webapps using <ResourceLink> to see if it works.
I used this setup before to read from both apps but never tried to write from one. So not sure if it will work.
Actually, it is possible to access others JNDI resources, if the servlet implements org.apache.catalina.ContainerServlet. This interface has a org.apache.catalina.Wrapper attribute, that is "populated" by the container itself.
through that, I created a simple application to monitor resources.
BUT, I would like to do that in a listener, so my resource monitor could start when the container starts. Anyone knows a way?
I have a servlet that I would like to run within ColdFusion MX 7. I would like to make use of an existing ColdFusion DSN as a javax.sql.DataSource, if possible.
I thought something like
coldfusion.server.ServiceFactory.getDataSourceService().getDatasource(dsname);
would work, but unfortunately the servlet returns
java.lang.NoClassDefFoundError: coldfusion/server/ServiceFactory
That code will work fine, you just don't have ServiceFactory in your classpath. Ie, Java can't load that class. Try including a dependency on cfusion.jar from C:\CFusionMX7\lib.
It seems the simplest way to do this is to add an additional JNDI datasource into jrun-resources.xml. This can then be accessed in the conventional way:
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("mydatasource");
It does mean duplicating database connection configuration, but I would rather do this than work with the largely undocumented coldfusion.server.* classes.