5 Replies Latest reply on Jul 17, 2003 6:10 PM by jonlee

    Problem with remote client

    mcgee

      Hi all,

      I have some session beans in JBoss, as well as a few objects that an MBean I wrote makes accessible via JNDI (an MBean classic). I can access them all in servlets, JSPs, or anything running in the same JVM.

      When I try from a remote client, my JNDI lookups succeed, except that the objects I get are of the wrong class. My EJB lookups get me classes of type $Proxy0 et al, which don't implement my remote methods. I used a little reflection and saw that the proxy classes seem to have a getEJBObject() method.

      When I try and get references to the objects loaded by the MBean, I get objects of type javax.naming.Reference. I used getClassName() on these and they seem to refer to the objects I really want, but there's no way to get at them.

      Does this sound familiar to anyone? I'm assuming it's something simple I'm doing wrong.

      Thanks,
      McGee

        • 1. Re: Problem with remote client
          jonlee

          Post the snippet on your lookup and bean use code as that would help us understand where the problem might be. It sounds like you are not narrowing the reference but that is a wild guess.

          • 2. Re: Problem with remote client
            mcgee

            Thanks Jon. I've included my code sample below. Let me refine my problem. I was mistaken in thinking EJBs are a problem; I was carelessly forgetting I was getting a home interface impl, not the remote inf. Duh.

            I still I can't lookup up objects placed in JBoss' namespace. I get a javax.naming.Reference that seems to refer to the desired object (though I removed the code that checks the Reference.getClassName() for brevity).

            Thanks,
            McGee

            import java.util.Properties;
            import javax.naming.Context;
            import javax.naming.InitialContext;
            import javax.naming.NamingException;


            public class JndiLab
            {
            static private Context jndi;

            public static void main (String[] args)
            {
            try {

            Properties props = new Properties();
            props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
            props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
            props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
            jndi = new InitialContext(props);
            tryObject("fc/globals/SessionMap");

            } catch (Exception ex) { ex.printStackTrace(); }
            }

            static private void tryObject (String name) throws NamingException
            {
            Object obj = jndi.lookup(name);
            System.err.println("obj.getClass()="+obj.getClass());
            Class[] infs = obj.getClass().getInterfaces();
            System.err.println("Interfaces:");
            for (int i=0; i<infs.length; ++i)
            {
            System.err.println(infs);
            }
            }
            }

            • 3. Re: Problem with remote client
              jonlee

              OK. Everything is fine right until the point you try and use the raw returned object. Essentially the process is (for a stateless session bean as the simplest example case):
              Get the reference to the Home interface (which is the bean factory, if you will).
              Ask the bean factory to create an instance of the EJB (stateless session bean) - it does not necessarily create one, it may just drag it out of the pool ala "here's one I created earlier".
              Call a method on the EJB.
              Remove the instance of the EJB - does not necessarily destroy it, it may just send it back to the pool so the next incoming request can use it.

              So your code is going to look something like this:
              BinaryRetrieverHome home = null; // Home interface class
              try
              {
              // Does the same as your properties set up
              Properties jndiProps = new Properties();
              jndiProps.setProperty(JNDIPKGS, NPKGS);
              jndiProps.setProperty(JNDIFACTORY, NCFACTORY);
              jndiProps.setProperty(JNDIURL, NPURL);
              // Get a naming context
              InitialContext jndiContext = new InitialContext(jndiProps);

              // Get a reference to the Binary Retriever Bean Home via JNDI name or whatever
              Object ref = jndiContext.lookup("BinaryRetriever");

              // Narrow the definition to a recognisable class
              home = (BinaryRetrieverHome)PortableRemoteObject.narrow(ref, BinaryRetrieverHome.class);
              }
              catch(Exception e)
              {
              System.out.println(e.toString());
              e.printStackTrace();
              System.out.println("Unable to create BinaryRetriever home");
              }
              // Bean interface class
              BinaryRetriever instance = null;
              try
              {
              // Create an instance of the bean (you access via the remote interface)
              instance = home.create();
              // now use a method defined in the interface
              byte[] pdf = instance.getBinary("Index");
              // Dispose of thoughtfully
              instance.remove();
              }
              catch(Exception e)
              {
              System.out.println(e.toString());
              e.printStackTrace();
              System.out.println("Unable to access");
              }

              Hope that helps.

              • 4. Re: Problem with remote client
                mcgee

                Thanks Jon. I should have been more clear . . . I'm fine with EJBs (although I can get away with a cast instead of PortableObject.narrow() . . . I'll have to check that out). What I *can't* do is JNDI lookups on objects an MBean of mine puts in the JNDI namespace.

                Here's my MBean code . . . reads in a properties file of mine that contains JNDI name - class name pairs. It instantiates each class, and does a JNDI rebind() on each to the appropriate name. I can then do lookups on the name from a servlet/JSP/EJB, but not outside of the JBoss JVM.

                I think I'm making an obvious fundamental error here, but I can't think of what it might be.

                Thanks,
                McHee

                (code below)


                public void reload () throws NamingException
                {
                Context jndi = new InitialContext();
                ClassLoader cl = this.getClass().getClassLoader();

                Properties props = new Properties();
                InputStream in = cl.getResourceAsStream("globals.properties");

                try {

                // Load the properties in, & iterate over them
                props.load(in);
                Iterator iterKeys = props.keySet().iterator();
                String jndiNameStr, className;
                while (iterKeys.hasNext())
                {
                // Get the JNDI name string, make a javax.Naming.Name out of it, add the name to the list
                jndiNameStr = (String)iterKeys.next();
                Name jndiName = jndi.getNameParser("").parse(jndiNameStr);
                _globalNames.add(jndiName);

                // Get the class name, make a Class, then instantiate it
                className = props.getProperty(jndiNameStr);
                Class cls = Class.forName(className);
                Object obj = cls.newInstance();

                // Bind the new instance to the JNDI name
                System.out.println("jndiName = " + jndiName);
                NonSerializableFactory.rebind(jndiName, obj, true);

                System.out.println("Bound " + jndiName + " to " + cls.getName());
                }

                } catch (Exception ex)
                {
                ex.printStackTrace();
                }
                }

                • 5. Re: Problem with remote client
                  jonlee

                  OK. I'm with you now. I'm not a huge JNDI namespace expert but isn't this the same problem as binding a datasource and not being able to find it external to the JVM? You're probably getting something like "name not bound"?

                  I haven't had a hard look at the JBoss binding operations but I believe it is this issue. I guess if you look at the JBoss source code, it should tell you how the binding should be constructed for externally accessible names.