Wednesday, March 21, 2007

Print JNDI tree

At one point or another most of us would have wanted to see what was in the JNDI tree of the Application Server. This may have been because of a javax.naming.NameNotFoundException thrown by the application under development.

After scouring the internet and not finding a way to do this seemingly simple task, I put this together in about an hours time.

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;

public class JNDITree {
private Context context = null;

public static void main(String[] args) throws Exception {
new JNDITree().printJNDITree("");
System.out.println("DONE");
}

public JNDITree() throws NamingException {
setEnv();
}

/* Please modify this method or comment and use jndi.properties
*/
public void setEnv() throws NamingException {
Hashtable env = new Hashtable();
//OC4J
// env.put(Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory");
// env.put(Context.PROVIDER_URL, "ormi://172.16.x.x:12404");
// env.put(Context.SECURITY_PRINCIPAL, "admin");
// env.put(Context.SECURITY_CREDENTIALS, "welcome");
//JBOSS
// env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
// env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
// env.put(Context.PROVIDER_URL, "jnp://172.16.x.x:1099");
//WEBLOGIC
// env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
// env.put(Context.PROVIDER_URL, "t3://172.16.x.x:7001");


context = new InitialContext(env);
}

public void printJNDITree(String ct) {
try {
printNE(context.list(ct), ct);
} catch (NamingException e) {
//ignore leaf node exception
}
}

private void printNE(NamingEnumeration ne, String parentctx) throws NamingException {
while (ne.hasMoreElements()) {
NameClassPair next = (NameClassPair) ne.nextElement();
printEntry(next);
increaseIndent();
printJNDITree((parentctx.length() == 0) ? next.getName() : parentctx + "/" + next.getName());
decreaseIndent();
}
}

private void printEntry(NameClassPair next) {
System.out.println(printIndent() + "-->" + next);
}


private int indentLevel = 0;

private void increaseIndent() {
indentLevel += 4;
}

private void decreaseIndent() {
indentLevel -= 4;
}

private String printIndent() {
StringBuffer buf = new StringBuffer(indentLevel);
for (int i = 0; i < indentLevel; i++) {
buf.append(" ");
}
return buf.toString();
}



This seemed to have worked very well for me and I thought I'd share it incase any of you have the same need.
In case anyone has a better way of doing this, kindly comment.

P.S. Dont forget to edit the setEnv() method to set the InitialContext. Default values have been given for a few App Servers.
Alternatively, comment the method out and use jndi.properties with values corresponding to your application server.

9 comments:

Niksa Jakovljevic A.K.A. kSha said...

Great article!
It really helped me in resolving JNDI lookup problems.

Regards,

Niksa Jakovljevic

skyanchor said...

This is a useful program that unfortunately doesn't quite work with Websphere 6. I used "com.sun.jndi.cosnaming.CNCtxFactory" for the initial context factory and "iiop://localhost:2809" for the provider URL. This enabled a successful connection and the JNDI tree began listing. However, because of internal namespace links within Websphere, the JNDI tree is apparently in this case not the same simple tree data structure, and so the program recursed indefinitely. I got the recursion to limit itself by adding a line of code to return if the indentLevel exceeded a fixed value. However, that solution truncated longer paths.

I found the easiest solution for the integrated Websphere app server on IBM's Developer Works site:

"Navigate to the bin directory of the integrated WebSphere Application Server and execute the dumpNamespace script. For example, under Windows, this may be C:\IBM\RAD6\runtimes\base_v6\bin\dumpNameSpace.bat..."

Determine the fully-qualified JNDI name

Thomas Francart said...

Use this to print the JNDI tree of a JBoss server :
http://jboss.org/wiki/Wiki.jsp?page=DisplayTheJDNITreeWithTheJMXConsole.
Cheers
Thomas

Shirish said...

Great Utility. Every Java developer should know about such utilities. I have used this tp resolve javax.naming.NameNotFoundException exception.

Thanks and regards,
Shirish

homes for sale costa rica said...

perfect item!
It really helped me resolve the JNDI lookup. happiness could not find anything better.

Gabriel Bratescu said...

For WebSphere you can use com.ibm.websphere.naming.DumpNameSpace class. It has a method generateDump(context) that prints out the jndi tree.

John Wong said...

Hi, thanks a lot for such a great post. I would be really thankful to you if you can help me further. Actually I have created a EJB project and added the same in EAR and deployed the EAR on my weblogic. When i execute your code below the output:

//OUTPUT-START
-->APP_EAREJB_30_Stateless_jarCalculatorService_Home: weblogic.rmi.cluster.ClusterableRemoteObject
//OUTPUT-END

I tried the below code:
//START-CODE
weblogic.rmi.cluster.ClusterableRemoteObject clusterableRemoteObject = (weblogic.rmi.cluster.ClusterableRemoteObject) ctx.lookup("APP_EAREJB_30_Stateless_jarCalculatorService_Home");
//END-CODE

but, below is the error;
//START-ERROR
java.lang.ClassCastException: weblogic.ejb.container.internal.StatelessEJBHomeImpl_1036_WLStub cannot be cast to weblogic.rmi.cluster.ClusterableRemoteObject
at stateless.CalculatorServiceClient.main(CalculatorServiceClient.java:44)
//END-ERROR

Please let me know how to get the EJB JNDI name so that I can execute context.lookup("EJB_JNDI_NAME");

Anonymous said...

Great!

Anonymous said...

Great article!