Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a JNDI datasource created by another application with Tomcat

Tags:

java

tomcat

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

like image 617
albertototo Avatar asked Dec 09 '25 22:12

albertototo


2 Answers

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

like image 96
Martín Schonaker Avatar answered Dec 12 '25 11:12

Martín Schonaker


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.

like image 36
jarnbjo Avatar answered Dec 12 '25 13:12

jarnbjo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!