feedburner
Enter your email address:

Delivered by FeedBurner

feedburner count

How to use JNDI with your J2SE application

Labels: , , , , ,

Have you ever wished you could have a JNDI (Java Naming and Directory Interface) server in your J2SE application? Do you need to unit test a Java class which gets its resources from JNDI? Well, you can. One of the nice things about JBoss is that it's Java open source project and that it's built from different components which can be used own their own. One of these components is the Java Naming Provider (JNP). Using the JBoss JNP we can add naming abilities to our J2SE application.

What we need is the following Java jars files:

   jnpserver.jar
jbossall-client.jar
log4j.jar
Of course we need to have a log4j configuration file (log4j.properties or log4j.xml) in our Java classpath.

In order to start the JNP we need to write the following code
  System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");

NamingBeanImpl jnpServer = new NamingBeanImpl();
jnpServer.start();

This will start the JNP in a different thread.

We can put the following jndi.properties file in the classpath
   java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
and then we can remove the System.setProperty(...) from the code.

Now lets see how we can use it to test JDBC code which gets its connection to the database from a DataSource object which is bound to JNDI Using JUnit and DbUnit.
Here is the class which we want to test:
public class DatabaseClass {

public static final String DB_JNDI_NAME = ...

public Connection getConnection() throws SQLException, NamingException {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(DB_JNDI_NAME);
return ds.getConnection();
}

public void insertData() {

Connection con = null;
try {
con = getConnection();
...
...
}
...
}

You can see that the method gets the connection to the database from JNDI.
Here is the JUnit test class:
public class TestClass {

@Test
public void testData() throws Exception {
System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");

DataSource ds = new EmbeddedDataSource();
((EmbeddedDataSource) ds).setUser("");
((EmbeddedDataSource) ds).setPassword("");
((EmbeddedDataSource) ds).setDatabaseName("testdb");
((EmbeddedDataSource) ds).setCreateDatabase("create");

NamingBeanImpl jnp = new NamingBeanImpl();
jnp.start();

Context initContext = new InitialContext();
initContext.createSubcontext(DatabaseClass.DB_JNDI_NAME);
initContext.rebind(DatabaseClass.DB_JNDI_NAME, ds);

DatabaseClass db = new DatabaseClass();
db.insertData();

// assert the database content using DbUnit
}
}

Then we can use DbUnit to assert the content in the database with the expected content. This way we can unit test the Class although it relies on the J2EE application server naming service.

Some problems you might encounter:
  Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/logging/Logger at org.jnp.server.NamingBeanImpl.(NamingBeanImpl.java:48)
You need to add jbossall-client.jar to your classpath.

I used to run the JNP by writing the following Java code:
  org.jnp.server.Main.main(new String[] {});
as opposed to
   NamingBeanImpl jnpServer = new NamingBeanImpl(); jnpServer.start();
The last time I tried, I got the following exception:
  java.lang.NullPointerException
at org.jnp.server.Main.getNamingInstance(Main.java:301)
at org.jnp.server.Main.initJnpInvoker(Main.java:354)
at org.jnp.server.Main.start(Main.java:316)
at org.jnp.server.Main.main(Main.java:104)
Looking at the source code I noticed the NamingBeanImpl class and Scott Stark comment
  * A naming pojo that wraps the Naming server implementation. This is
* a refactoring of the legacy org.jnp.server
Using the NamingBeanImpl class I managed to solve the problem.

0 comments:

Post a Comment