4 Replies Latest reply on Apr 3, 2003 8:19 AM by Miguel

    Problem invoking method on remote EJB from another EJB

    GadgetMan Newbie

      I have a problem in trying to invoke a method on another EJB which is in another server from an EJB on one server. The 2 EJBs are stateless session beans. I am using 2 instances of JBoss for the 2 EJBs. Instance 1 of JBoss is on the standard port of 1099, whereeas instance 2 of JBoss is on port 11099. When I try to invoke the create method on EJB B from EJB A, I get a RemoteException indicating an rmi.MarshallException. In detail, it gives me a NotSerializableException. I find out I do get back a reference to the home interface of EJB B. I don't know why this is the case. If I invoke an EJB in the same server then it works. I would be grateful for any help anyone can provide. Thanks.

      I've also added the <ejb-ref> in the ejb-jar.xml and jboss.xml for EJB A, as mentioned from www.jboss.org/online-manual/HTML/ch05s13.html.

      Here's the code for EJB A:

      package A;

      import java.rmi.RemoteException;
      import javax.rmi.PortableRemoteObject;
      import javax.naming.InitialContext;
      import javax.naming.Context;
      import javax.naming.NamingException;
      import javax.ejb.EJBException;
      import java.net.MalformedURLException;
      import java.rmi.NotBoundException;
      import A.*;
      import java.util.Properties;
      import java.io.*;

      public class Bean implements javax.ejb.SessionBean
      {

      // for stateful session bean
      public javax.ejb.SessionContext ejbContext;
      public javax.naming.Context jndiContext;

      public void ejbCreate()
      {

      System.out.println("ABean: create()");

      }

      public String Method1(String user)
      throws RemoteException {
      System.out.println("ABean: method1");
      return user;
      }







      public void sendToB(String user)
      throws RemoteException {
      System.out.println("ABean: Sending to B ");

      try {
      Context jndiContext = getInitialContext();
      //InitialContext jndiContext = new InitialContext();
      System.out.println("Got context");
      Object ref = jndiContext.lookup("ejb/BBean");
      System.out.println("Found B in JNDI context");

      B.BeanHomeRemote home = (B.BeanHomeRemote)
      PortableRemoteObject.narrow(ref,B.BeanHomeRemote.class);
      //B.BeanHomeRemote home = (B.BeanHomeRemote) PortableRemoteObject(ref);
      System.out.println("Starting to invoke on B ");
      if (home != null) {
      System.out.println("Got reference to EJB B");
      }
      else {
      System.out.println("No reference to EJB B");
      }
      B.BeanRemote b = home.create();
      if (b != null) {
      System.out.println("EJB B remote interface is not null");
      }
      else {
      System.out.println("EJB B remote interface is null");
      }
      b.Method1(user);

      }
      /*catch (MalformedURLException murle) {
      System.out.println();
      System.out.println(
      "MalformedURLException");
      System.out.println(murle);
      } */
      catch (RemoteException re) { System.out.println();
      System.out.println(
      "RemoteException");
      System.out.println(re);
      }
      catch (Throwable t) { t.printStackTrace();}


      }



      public void ejbRemove(){}
      public void ejbActivate(){}
      public void ejbPassivate(){}


      public void setSessionContext(javax.ejb.SessionContext cntx){
      ejbContext = cntx;
      try {
      jndiContext = new InitialContext();
      }
      catch (NamingException ne) {
      throw new EJBException(ne);
      }
      }

      protected Object getHome(String name, Class type) {
      try {
      Object ref = jndiContext.lookup(name);
      return PortableRemoteObject.narrow(ref, type);
      }
      catch (NamingException ne) {
      throw new EJBException(ne);
      }
      }

      static public Context getInitialContext() throws Exception
      {
      //context initialized by jndi.properties file

      String jndiFile = "";

      java.util.Properties p = new java.util.Properties();
      p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
      p.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces");

      jndiFile = "E:\\Code\\B\\jndi\\jndi.properties";

      java.util.Properties jndi_prop = new Properties();
      jndi_prop.load(new FileInputStream(jndiFile));
      // look for Context.PROVIDER_URL in jndi file
      String jndi_url = jndi_prop.getProperty("java.naming.provider.url");
      //p.put(Context.PROVIDER_URL, "localhost:1099");
      p.put(Context.PROVIDER_URL, jndi_url);

      return new javax.naming.InitialContext(p);

      }

      }

      Here's the code for EJB B:

      package B;

      import java.rmi.RemoteException;
      import javax.rmi.PortableRemoteObject;
      import javax.naming.InitialContext;
      import javax.naming.Context;
      import javax.naming.NamingException;
      import javax.ejb.EJBException;
      import java.net.MalformedURLException;
      import java.rmi.NotBoundException;
      import java.util.Properties;
      import java.io.*;

      public class Bean implements javax.ejb.SessionBean
      {

      public javax.ejb.SessionContext ejbContext;
      public javax.naming.Context jndiContext;

      public void ejbCreate()
      {

      //System.out.println("BBean: create()");

      }

      public String Method1(String user)
      throws RemoteException {
      System.out.println("BBean: method1");
      return user;
      }

      public void ejbRemove(){}
      public void ejbActivate(){}
      public void ejbPassivate(){}

      public void setSessionContext(javax.ejb.SessionContext cntx){
      ejbContext = cntx;
      try {
      jndiContext = new InitialContext();
      }
      catch (NamingException ne) {
      throw new EJBException(ne);
      }
      }

      protected Object getHome(String name, Class type) {
      try {
      Object ref = jndiContext.lookup(name);
      return PortableRemoteObject.narrow(ref, type);
      }
      catch (NamingException ne) {
      throw new EJBException(ne);
      }
      }

      static public Context getInitialContext() throws Exception
      {
      //context initialized by jndi.properties file

      String jndiFile = "";

      java.util.Properties p = new java.util.Properties();
      p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
      p.put(Context.URL_PKG_PREFIXES, "jboss.naming:org.jnp.interfaces");

      jndiFile = "E:\\Code\\B\\jndi\\jndi.properties";

      java.util.Properties jndi_prop = new Properties();
      jndi_prop.load(new FileInputStream(jndiFile));
      // look for Context.PROVIDER_URL in jndi file
      String jndi_url = jndi_prop.getProperty("java.naming.provider.url");
      //p.put(Context.PROVIDER_URL, "localhost:1099");
      p.put(Context.PROVIDER_URL, jndi_url);

      return new javax.naming.InitialContext(p);

      }


      }

      Here's the ejb-jar.xml for EJB A:

      <?xml version="1.0"?>

      <!DOCTYPE ejb-jar PUBLIC
      "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
      "http://java.sun.com/dtd/ejb-jar_2_0.dtd">

      <ejb-jar>

      <enterprise-beans>


      <ejb-name>AEJB</ejb-name>
      A.BeanHomeRemote
      A.BeanRemote
      <ejb-class>A.Bean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
      <ejb-ref>
      <ejb-ref-name>ejb/BBean</ejb-ref-name>
      <ejb-ref-type>Session</ejb-ref-type>
      B.BeanHomeRemote
      B.BeanRemote
      </ejb-ref>

      </enterprise-beans>

      <assembly-descriptor>
      <security-role>

      This role represents everyone who is allowed full access to the beans.

      <role-name>everyone</role-name>
      </security-role>

      <method-permission>
      <role-name>everyone</role-name>

      <ejb-name>AEJB</ejb-name>
      <method-name>*</method-name>

      </method-permission>

      <container-transaction>

      <ejb-name>AEJB</ejb-name>
      <method-name>*</method-name>

      <trans-attribute>Required</trans-attribute>
      </container-transaction>
      </assembly-descriptor>

      </ejb-jar>

      Here's the jboss.xml for EJB A:

      <?xml version="1.0"?>


      <enterprise-beans>

      <ejb-name>AEJB</ejb-name>
      <jndi-name>A</jndi-name>
      <ejb-ref>
      <ejb-ref-name>ejb/BBean</ejb-ref-name>
      <jndi-name>jnp://localhost:11099/ejb/BBean</jndi-name>
      </ejb-ref>

      </enterprise-beans>


      The home and remote interfaces for EJB B are packaged in the A.jar which is deployed on JBoss instance 1.

      Any ideas what's going wrong, I've been tackling this for couple of days, and looking at various posts on the Internet, but haven't solved the problem. I am sure this has been addressed before, but I can't easily find it. It's getting pretty frustrating now!

      Thanks for any help that anyone can provide, I am new to EJBs.

        • 1. Re: Problem invoking method on remote EJB from another EJB
          GadgetMan Newbie

          Is it correct to put in the <jndi-name> tag of jboss.xml for EJB A

          <jndi-name>jnp://localhost:11099/ejb/bBean</jndi-name>

          I am thinking this is where the failure is happening. What exactly is the syntax for specifying the jndi-name of
          a remote EJB from another server.

          The remote EJB which I am accessing from EJB A (EJB B) is deployed on localhost:11099 since I am running two instances of JBoss on my machine.

          Hope that helps.

          Awaiting any replies on this.

          • 2. Re: Problem invoking method on remote EJB from another EJB
            GadgetMan Newbie

            I am wondering if maybe the <jndi-name> tag in jboss.xml of EJB A is causing the RemoteException problem with NotSerialiableException. What is the correct way of specifying the jndi-name of a remote EJB in another JBoss server?

            Right now, I have my jboss.xml <jndi-name> as this:

            <jndi-name>jnp://localhost:11099/ejb/BBean</jndi-name>

            In the jboss.xml of EJB B (the remote EJB), I have:

            <jndi-name>ejb/BBean</jndi-name>

            And in my Bean.java for EJB A that is calling EJB B, I have:

            Object ref = Object ref = jndiContext.lookup("ejb/BBean");

            So I am at a loss, can someone tell me where I am going wrong?

            Thanks for any help.

            • 3. Re: Problem invoking method on remote EJB from another EJB
              GadgetMan Newbie

              Ok I solved the problem. If anybody else has this problem do this:

              TransactionManager manager = null;
              Transaction tx = null;

              try{
              Context context = new InitialContext();
              manager = (TransactionManager) context.lookup("java:/TransactionManager");
              tx = manager.suspend();
              }catch(Exception e){
              e.printStackTrace();
              }

              try {
              // do your remote EJB lookup and invocations
              } catch (Exception e) {
              e.printStackTrace();
              }
              finally {
              try{
              if(manager != null && tx != null){
              manager.resume(tx);
              }catch(Exception e){
              e.printStackTrace();
              }
              }

              From reading posts in this group and in other EJB groups, the problem exists with the JBoss Transaction Manager. Check out my post here on Sun's Java forums for the full story behind this: http://forums.java.sun.com/thread.jsp?forum=13&thread=374496&tstart=0&trange=15

              I had to gather this from various posts so I thought it would be MUCH easier to post it here. I know others will run into the same problem and instead of wasting couple of days figuring this out, the solution is here.

              • 4. Re: Problem invoking method on remote EJB from another EJB
                Miguel Newbie


                Dear all,

                I have a similar problem to the one exposed above.

                We want to use a method of EJB A from EJB B. And then I got:

                13:12:14,755 ERROR [STDERR] java.rmi.MarshalException: error marshalling
                arguments; nested exception is:
                java.io.NotSerializableException: org.jboss.tm.TransactionImpl


                What I can understand is that call works in one server and not in a another one (same
                code, same JDK, same version of tomcat, Jboss). I stumped.

                Could anyone give any clue of what could be happening? I tarred the jboss directory
                from the PC where the EJB seems to work and untarred in the other PC, and still
                doesnt work!

                Many thanks

                Miguel