A little more information:
The ServiceLocator is a Singleton object which runs as part of the server, and has its InitalContext bound the first time it's used (this happens in the ServiceLocator Singleton's constructor). The weirdness I'm experiencing is that it completes several lookups successfully before bombing on a lookup which uses the same JNDI name of a lookup that previously worked -- it literally works on one call and then fails on the next. The difference between the times it works and the time it doesn't is that the successful ServiceLocator method invocations originate within Servlets or EJBs and the unsuccessful invokation is made from within a JMX component. Still it's the same ServiceLocator Singleton, with the same internal InitialContext, so it would follow that the InitialContext would never lose a binding, regardless of the type of component that calls the method which does a lookup.
To further illustrate here's the scenario I'm dealing with:
1. The server is started.
2. The client is started.
3. All is well -- the client calls the servlets, which either (a) call the ServiceLocator to get EJBs or (b) invoke JMX services (MBean methods) which call the ServiceLocator to get EJBs.
4. The server is restarted.
5. The client makes a call to a servlet.
6. The servlet makes a call to the ServiceLocator method to get an EJB, and within that EJB the ServiceLocator is again called to get another EJB:
a. Lookup of java:comp/env/ejb/EJBOne is successful
b. Lookup of java:comp/env/ejb/EJBTwo is successful
7. The client calls a method on a JMX service (MBean) which internally uses the ServiceLocator to get an EJB. In this case the lookup fails:
c. Lookup of java:comp/env/ejb/EJBThree fails with the following exception stack trace:
javax.naming.NameNotFoundException: env not bound
7. The client receives the error and calls another servlet to refresh itself. This servlet looks up the same EJB which the JMX service was trying to lookup, and this time the ServiceLocator has no trouble finding it:
b. Lookup of java:comp/env/ejb/EJBThree is successful
In the ServiceLocator's lookup method I have added debug code to show the HashCode of the InitialContext being used, and in fact it is the same InitialContext being used each time.
What I think is happening is that normally in my application when the JMX components invoke ServiceLocator methods these methods are never doing lookups and are always getting objects previously cached by lookups made by previous ServiceLocator method calls made the Servlets or EJBs. In other words the above scenario is the only time a JMX component is invoking a ServiceLocator method in which the requested object isn't already cached and the lookup actually needs to happen. The "java:comp/env" name is somehow not available within the context of JMX, and hence the lookup fails.
So it appears that within the context of normal (non-JMX) components the JNDI name "java:comp/env" is bound to the InitialContext, but within the context of a JMX component the InitialContext temporarily loses this binding. Is this the really case? If so can someone point me to a reference in which this behavior explained?
The bonehead mistake which was causing the problem: I was always looking up my EJBs with "java:comp/env/" prefixed to the actual JNDI name of the EJB. Now that I've removed this everything works as it should.
How were you able to successfully bind to objects on java:comp/env? I'm running JBoss 4.0.0 and I can only bind datasources on java:. However, the code I'm using looks up the datasource using java:comp/env.
When I look at the JNDIView MBean, it appears there's a comp subcontext under java:, but if you try binding the datasource to java:comp/datasource or even java:comp/env/datasource, the log messages on the console say that the datasource is successfully bound to java:comp/datasource or java:comp/env/datasource, but when the web-app's code tries looking it up, I get a NamingException saying that env is not bound, and when you look at the list generated by the JNDIView MBean, you don't see the bound datasource or even the env subcontext.
Which files do I need to configure to add a java:comp/env namespace to JBoss's JNDI?
I noticed a number of other people are having the same or very similar problems and no one replies to their posts. Why is that?
OK, I have 2 solutions to my problem.
1. Upgrade to JBoss 4.0.3. Using that version, your servlet code can lookup a datasource on java:comp/env and JBoss will give the corresponding datastore that you have bound to java:/. For example, if the code is using java:comp/env, and your web.xml's resource-ref element has testDS as its name, your jboss-web.xml's resource-ref can map the testDS to whatever jndi name you choose under the java: namespace (say java:/realDS). Just make sure that your datasource's *-ds.xml file's jndi-name element is the same as it is in jboss-web.xml minus the java:. So in this case, it would be /realDS.
2. Change the servlet code to lookup java:/ + the datasource name. So if your web.xml's resource-ref element's name is testDS, your code needs to lookup the string "java:/testDS". You should then make sure your JBoss setup binds the datasource under the root of the java: namespace. In other words, your jboss-web.xml file has a resource-ref element that maps the testDS from your web.xml file to the jndi name java: + whatever the jndi-name element in your *-ds.xml file is. For example, if the *-ds.xml file has a jndi-name element with the value of /realDS, your jboss-web.xml file should have a resource-ref element that maps your web.xml's resource-ref's name to the jndi name of java:/realDS.