4 Replies Latest reply on Feb 17, 2013 11:36 PM by Holger L

    JNDI Naming confusion

    Mike Miller Newbie

      I am researching a migration from JBoss 4.2.3.GA to AS7.x and have been struggling with the new JNDI processing.   I read both of the following links

       

      along with many others because we the migration would also include moving from EJB 2.1 up to EJB 3.x.   Tonight, after re-reading the first link from above, I think part of my confusion has been resolved.

       

      My initial research was with the "ejb-remote" project from the quick starts, specifically for the stateless beans.   One of the things adding to my confusion was the log statement that logs all of the bindings created for this session bean.  I was under the impression that I should be able to lookup the session bean using each of the jndi names listed below.

       

      19:56:13,406 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings for session bean named CalculatorBean in deployment unit deployment "jboss-as-ejb-remote-app.jar" are as follows:

       

           java:global/jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator

           java:app/jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator

           java:module/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator

           java:jboss/exported/jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator

           java:global/jboss-as-ejb-remote-app/CalculatorBean

           java:app/jboss-as-ejb-remote-app/CalculatorBean

           java:module/CalculatorBean

       

      So I decided to write an EJBClient program that attempted to do a jndi lookup for each of these jndi names and do it without any magic files like the jboss-ejb-client.properties file.  I added all the jndi properties explicitly before creating the InitialContext.  Exactly NONE of these strings worked, but I knew that the quick start client worked, so after reviewing that code, I added an additional entry to the array of jndi names

       

      "ejb:/jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator"

       

      Re-running the program, now I got 1 success - better but not really what I was expecting.   So after re-reading the first link AGAIN, I came across two very important points:

       

      1. Note: Since the JNDI name that you use on the client side is always relative to java:jboss/exported namespace, you shouldn't be prefixing the java:jboss/exported/ string to the JNDI name.
      2. Note that only the java:jboss/exported/ namespace is available to remote clients.

       

      So back to my test program - I took each of the names from the log statement, repeated them and removed the first part of each string on the newly repeated line, so java:app/, java:module/ and java:global/, java:jboss/exported/ and ran again.  Now I got a couple more successful lookups - mostly because by removing the namespace (is that the correct term?), some of the strings were basically resolving to the same string.

       

      Is it safe to say that we can ignore all but the java:jboss/exported/ naming bindings, at least for remote clients, since that is the only name space available to remote clients?   If so, why are all those other bindings included in the log?

       

      I have attached my sample program in case there were any questions about how I created my test.

        • 1. Re: JNDI Naming confusion
          Mike Miller Newbie

          I am going to answer my own question after resolving the problem, at least as far as I can tell.  Please feel free to correct me if I am wrong.   One of the main points of confusion was the new JNDI formats required by EJB 3.1.   Another was not realizing that I could NOT use the exact same code on the client AND server side.  In JBoss 4.2.3 we had a Service Locator that filled in the provider_url and the initial context factory settings and we looked up the remote EJB interfaces the same, whether we were on the server or the JNLP launched client.

           

          Below is a sample program that executes both versions of the remote client lookups in AS7 using the ejb-remote deployment from the 7.1.1 Quick Starts.  The expectation is that for the first of lookups, the first string/lookup is successful and the second (ejb:/ format) is not.   Then I add the Context.URL_PKG_PREFIXES property with value "org.jboss.ejb.client.naming" to the jndiProps and repeat the lookups.   Now the expectation is that both are successful.   This covers the client side loading.   Read below for the easier part - server side loading.

           

          import javax.naming.Context;
          import javax.naming.InitialContext;
          import javax.naming.NamingException;
          
          import java.util.Hashtable;
          
          public class EJBClient {
          
               private static String[] JNDINAME = {
                    "jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator", 
                    "ejb:/jboss-as-ejb-remote-app/CalculatorBean!org.jboss.as.quickstarts.ejb.remote.stateless.RemoteCalculator" 
               };
               
               private Hashtable jndiProps;
               
               public EJBClient() {
                 // setup 'base' jndi properties - no jboss-ejb-client.properties being picked up from classpath!
                 jndiProps = new Hashtable();
                    jndiProps.put("java.naming.factory.initial","org.jboss.naming.remote.client.InitialContextFactory");
                    jndiProps.put(InitialContext.PROVIDER_URL, "remote://localhost:4447");
                    jndiProps.put("jboss.naming.client.ejb.context", true);
                  
                    // needed for remote access - remember to run add-user.bat
                    jndiProps.put(Context.SECURITY_PRINCIPAL, "client");
                    jndiProps.put(Context.SECURITY_CREDENTIALS, "password");
               }
               
              public void doLookups() {
                   // the 'exported' namespace
                   for (int i = 0; i < JNDINAME.length; i++) {
                         lookup(JNDINAME[i]);
                    }
                   
                  
                   // This is an important property to set if you want to do EJB invocations via the remote-naming project
                  jndiProps.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
                  
                  // now with the ejb
                  for (int i = 0; i < JNDINAME.length; i++) {
                         lookup(JNDINAME[i]);
                    }
              }
              
              private void lookup(String name) {
                   System.out.println("Lookup name="+name);
                   
                   Context ctx = null;
                  try {
                         ctx = new InitialContext(jndiProps);
                         Object ref = ctx.lookup(name);
                         System.out.println("...Successful");
                    } catch (NamingException e) {
                         System.out.println("...Failed");
                         //System.out.println(e.getMessage());
                         e.printStackTrace();
                    } finally {
                         if (ctx != null) {
                              try {
                                   ctx.close();
                              } catch (NamingException e) {}
                         }
                    }
              }
              
              public static void main(String[] args) throws Exception {
                   EJBClient client = new EJBClient();
                   client.doLookups();
                   
                   System.out.println("Done!");
              }
              
          }
          
          

           

          The other part of my problem was trying to use the same code on the server that I was using from the client side - WRONG!   Looks like for our migration from JBoss 4.2.3 to AS7, we are going to have to use different code to load services from the server and client.  Below is the short snippet of code used to load the services when running on the server within AS7.   The key being that the initial context factory is different from the client side value, plus more of the bindings are available on the server side than on the client side.

           

              Hashtable jndiProps = new Hashtable();
              jndiProps.put("java.naming.factory.initial", "org.jboss.as.naming.InitialContextFactory");
              ctx = new InitialContext(jndiProps);
              Object ref = ctx.lookup(jndiName);
          

           

          Hope this helps others running into the same types of confusion!

          • 2. Re: JNDI Naming confusion
            rodakr Novice

            just small hint for server side:

             

            ctx = new InitialContext();

            Object ref = ctx.lookup(jndiName);

             

            You don't need to set any  thing on context on server side....( at least for jboss server to jboss  server communication )

            This way chnace are bigger, migrating next time, you don't need to change it :-)

            1 of 1 people found this helpful
            • 3. Re: JNDI Naming confusion
              Mike Miller Newbie

              Thanks for the update.  I went back and re-tested and found a case where our 'old'/existing code was biting me but by setting the naming factory setting it got me past the error.  Currently we save the naming factory and provider url in the database and that row gets passed to our service factory that loads the services.  It was still setup for using JNP and port 1099.

              • 4. Re: JNDI Naming confusion
                Holger L Newbie

                Hi,

                 

                Great post which clarifies a lot of the JNDI confusion. Are there any best practices how to define and expose the JNDI names? We're trying to define and expose the JNDI name via the actual class:

                 

                For example if we have the following EJB deployed in an EAR app:

                 

                {code}

                @Remote

                publi interface FeeService {

                 

                     public static final String REMOTE_JNDI =  "java:global/commission-engine/commissions-ejb-client/FeeServiceBean!com.macquarie.msg.ce.remote.service.FeeService";

                     public static final String REMOTE_CONTAINER_JNDI = "commission-engine/commissions-ejb-client/FeeServiceBean!com.macquarie.msg.ce.remote.service.FeeService";

                ...

                }

                {code}

                1. Within the same EAR app, any reference should be automatically resolved e.g.:

                {code}

                @EJB

                FeeService feeService

                {code}

                 

                2. An EJB in a different EAR would reference the EJB  by using the portable JNDI name above, e.g.

                {code}

                @EJB(mappedName=FeeService.REMOTE_JNDI)

                {code}

                 

                3. An EJB on a different server or a remote client would reference the EJB without the "java:global"

                {code}

                FeeService feeService = (FeeService) ctx.lookup(FeeService.REMOTE_CONTAINER_JNDI );

                {code}

                 

                Is there any way to consolidate this naming into ONE REMOTE_JNDI instead of having to define 2? At this stage it doesn't feel very portable...

                 

                Thanks