Java Tutorial - Java Scipt : Browsing JNDI

Java Tutorial - Java Scipt :

Browsing JNDI


Getting the JNDI name correct in the client code is important. The JNDI name is what the application uses to look up the data source with JNDI. A common mistake is to forget to place jdbc/ in front of the JNDI name for a Data Source in Tomcat. Some application servers enforce the jdbc/ subcontext for data sources. Others, like Tomcat, just suggest it. It can be frustrating to know that a data source is supposed to be configured for one name but the lookup fails. This program tries to address this issue by providing a basic JNDI browser. The servlet below is designed to walk through a JNDI context (starting at java:comp/env) and print information about any Data Sources that are
found. When it encounters a subcontext, it will walk through that as well.

import java.io.*;
import java.net.*;
import java.text.DateFormat;
import java.util.Date;
import javax.naming.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.DataSource;

public class SnoopJndi extends HttpServlet
{
private String printJndi( String jndiStart )
{
String rStr = null;
Context initCtx = null;
StringBuffer sb = new StringBuffer(128);
try
{
initCtx = new javax.naming.InitialContext();
NamingEnumeration list = null;

if( jndiStart.equals(“”) )
jndiStart=”java:comp/env”;
sb.append(“\nContext ==>”);
sb.append( jndiStart );
sb.append( “\n” );

list = initCtx.listBindings(jndiStart);
Binding item = null;
while (list.hasMore())
{
item = (Binding)list.next();
sb.append( jndiStart );
sb.append(“/”);
sb.append( item.toString() );
sb.append( “\n” );
if( item.getObject() instanceof javax.naming.Context)
{
sb.append( printJndi( jndiStart+”/”+item.getName()) );
}
}
rStr = sb.toString();
}
catch( Exception e )
{
rStr = e.toString();
}
return( rStr );
}

private String today()
{
Date now = new Date();
DateFormat dateFormatter = DateFormat.getDateTimeInstance();
return dateFormatter.format( now );
}

public void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType(“text/plain”);
PrintWriter out = response.getWriter();
out.println( “Date:”+today());
out.println( printJndi( “” ) );
out.close();
}
}

First, note that the response type is text/plain. This simplifies the servlet by not requiring HTML tags. The simple text output is fine for our purposes at this time. The printJndi method builds a string that will be returned and sent as the response generated by doGet().

The printJndi method does all of the interesting work. First, it gets an InitialContext (this is necessary because an InitialContext is not synchronized and so should not be shared with all other thread instances). Then, it gets a list
of binding within the context as shown in the following line:

list = initCtx.listBindings(jndiStart);

The argument jndiStart provides the initial argument for the function and presents the current base path within the JNDI hierarchy that the list will be generated for. A while loop is used to iterate through the list, using the
toString method to print a string representation of each binding on the list. The line below shows how each element is tested to see if it is also a context:

if( item.getObject() instanceof javax.naming.Context)

If the item is a context, the printJndi methods recurses and calls itself to add the subcontext information as follows:

sb.append( printJndi( jndiStart+”/”+item.getName()) );

Any exceptions that may occur are caught and returned as the return string. Once compiled this servlet can be installed into the classes directory of any Web application to provide a convenient information tool. The relevant fragment for the web.xml deployment descriptor is:

<servlet>
<servlet-name>SnoopJndi</servlet-name>
<display-name>SnoopJndi</display-name>
<description>Jndi Snooper</description>
<servlet-class>SnoopJndi</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SnoopJndi</servlet-name>
<url-pattern>/servlet/SnoopJndi</url-pattern>
</servlet-mapping>

When deployed with a Web application named snoopy the URL for accessing the servlet is:


The result should look something like the following:

Date:Feb 17, 2003 10:10:29 PM

Context ==>java:comp/env
java:comp/env/jdbc:
org.apache.naming.NamingContext:org.apache.naming.NamingContext@969c29

Context ==>java:comp/env/jdbc
java:comp/env/jdbc/hsqltest:
org.apache.naming.ResourceRef:ResourceRef[className=javax.sql.DataSource
,factoryClassLocation=null,factoryClassName=org.apache.naming.factory.Re
sourceFactory,{type=scope,content=Shareable},{type=auth,content=Containe
r},{type=url,content=jdbc:hsqldb:c:/openjava/hsqldb/data/hsqltest},{type
=password,content=},{type=driverClassName,content=org.hsqldb.jdbcDriver}
,{type=username,content=sa}]
Note that the line of output that begins with org.apache.naming is displayed
as a single line in the browser.