Hello ppl,

I've fixed the problem with UndeclaredThrowableException.

At first I thought that it might have been a bug in JDK, so I started work
on a reproducable example. I made 1 jar (main.jar) from which I loaded 2
other jars (server.jar, client.jar). This lead to the
UndeclaredThrowableException. Then I returned the exception (instead of
throw) which lead to a ClassCastException. On hindsight I should have
expected this because identical twin classes loaded from different places
are not the same classes. This lead me to think why do argument objects work
correctly. Well I found out in JRMPContainerInvoker that they are
marshalled, but the exception isn't. So I made a quick & dirty fix.

Can someone apply a slow & clean fix to the CVS repository? :-)

Grtz,

Carlo


What follows is the complete listing of a working JRMPContainerInvoker.
Note: It has been mangled by the wonderfull micros$ft tool: outlook express.

===8<===

/*
 * jBoss, the OpenSource EJB server
 *
 * Distributable under GPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.ejb.plugins.jrmp.server;

import java.awt.Component;
import java.beans.beancontext.BeanContextChildComponentProxy;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.rmi.ServerException;
import java.rmi.RemoteException;
import java.rmi.MarshalledObject;
import java.rmi.server.RemoteServer;
import java.rmi.server.UnicastRemoteObject;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Properties;

import javax.ejb.EJBMetaData;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.naming.Name;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NameNotFoundException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.jboss.ejb.MethodInvocation;

import org.jboss.ejb.Container;
import org.jboss.ejb.ContainerInvokerContainer;
import org.jboss.ejb.Interceptor;
import org.jboss.ejb.ContainerInvoker;
import org.jboss.ejb.plugins.jrmp.interfaces.RemoteMethodInvocation;
import org.jboss.ejb.plugins.jrmp.interfaces.HomeProxy;
import org.jboss.ejb.plugins.jrmp.interfaces.HomeHandleImpl;
import org.jboss.ejb.plugins.jrmp.interfaces.StatelessSessionProxy;
import org.jboss.ejb.plugins.jrmp.interfaces.StatefulSessionProxy;
import org.jboss.ejb.plugins.jrmp.interfaces.EntityProxy;
import org.jboss.ejb.plugins.jrmp.interfaces.GenericProxy;
import org.jboss.ejb.plugins.jrmp.interfaces.ContainerRemote;
import org.jboss.ejb.plugins.jrmp.interfaces.IteratorImpl;
import org.jboss.ejb.plugins.jrmp.interfaces.EJBMetaDataImpl;
import org.jboss.ejb.plugins.jrmp.interfaces.SecureSocketFactory;

import org.jboss.system.SecurityAssociation;

import org.jboss.logging.Logger;

import org.jboss.ejb.DeploymentException;
import org.jboss.metadata.XmlLoadable;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.EntityMetaData;
import org.jboss.metadata.SessionMetaData;

import org.w3c.dom.Element;

/**
 *      <description>
 *
 *      @see <related>
 *      @author Rickard Öberg ([EMAIL PROTECTED])
 *  @author <a href="mailto:[EMAIL PROTECTED]">Sebastien
Alborini</a>
 *      @author <a href="mailto:[EMAIL PROTECTED]">Marc Fleury</a>
 *      @version $Revision: 1.29 $
 */
public abstract class JRMPContainerInvoker
   extends RemoteServer
   implements ContainerRemote, ContainerInvoker, XmlLoadable
{
 static
 {
  System.err.println("*** using modified " +
JRMPContainerInvoker.class.getName());
  System.err.println("  - now marshalling exceptions");
 }

 private static class MarshalledException extends Exception
 {
  private MarshalledObject obj;

  public MarshalledException(Exception e)
   throws IOException
  {
   obj = new MarshalledObject(e);
  }

  public Exception getOriginalException()
   throws ClassNotFoundException, IOException
  {
   return (Exception) obj.get();
  }
 }

   // Constants -----------------------------------------------------
   protected final static int ANONYMOUS_PORT = -5;

   // Attributes ----------------------------------------------------
   protected boolean optimize = false;
   protected int unicastObjectPort = ANONYMOUS_PORT;
   protected Container container;
   protected String jndiName;
   protected EJBMetaDataImpl ejbMetaData;
   // The home can be one.
   protected EJBHome home;
   // The Stateless Object can be one.
   protected EJBObject statelessObject;

    protected HashMap beanMethodInvokerMap;
    protected HashMap homeMethodInvokerMap;

   // Static --------------------------------------------------------

   // Constructors --------------------------------------------------

   // Public --------------------------------------------------------
   public void setOptimized(boolean optimize)
   {
      this.optimize = optimize;
file://DEBUG  Logger.debug("Container Invoker optimize set to
'"+optimize+"'");
   }

   public boolean isOptimized()
   {
file://DEBUG  Logger.debug("Optimize in action: '"+optimize+"'");
      return optimize;
   }

   public EJBMetaData getEJBMetaData()
   {
      return ejbMetaData;
   }

   public abstract EJBHome getEJBHome();

   public abstract EJBObject getStatelessSessionEJBObject();

   public abstract EJBObject getStatefulSessionEJBObject(Object id);

   public abstract EJBObject getEntityEJBObject(Object id);

   public abstract Collection getEntityCollection(Collection ids);

   // ContainerRemote implementation --------------------------------
   public MarshalledObject invokeHome(MarshalledObject mimo)
      throws Exception
   {
      ClassLoader oldCl = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(container.getClassLoader());

      try
      {
         RemoteMethodInvocation rmi = (RemoteMethodInvocation)mimo.get();
         rmi.setMethodMap(homeMethodInvokerMap);
         Transaction tx = rmi.getTransaction();

         try
         {
      return new MarshalledObject(container.invokeHome(new
MethodInvocation(null, rmi.getMethod(), rmi.getArguments(), tx,

rmi.getPrincipal(), rmi.getCredential() )));
         }
   catch(Exception e)
   {
    // Since marshalling causes a loss of the stacktrace I print it here.
    e.printStackTrace();
    throw new MarshalledException(e);
   }
      } finally
      {
         Thread.currentThread().setContextClassLoader(oldCl);
      }
   }

   public MarshalledObject invoke(MarshalledObject mimo)
      throws Exception
   {
      ClassLoader oldCl = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(container.getClassLoader());

      try
      {
         RemoteMethodInvocation rmi = (RemoteMethodInvocation)mimo.get();
         rmi.setMethodMap(beanMethodInvokerMap);
         Transaction tx = rmi.getTransaction();

         try
         {
    return new MarshalledObject(container.invoke(new
MethodInvocation(rmi.getId(), rmi.getMethod(), rmi.getArguments(), tx,

rmi.getPrincipal(), rmi.getCredential() )));
         }
   catch(Exception e)
   {
    // Since marshalling causes a loss of the stacktrace I print it here.
    e.printStackTrace();
    throw new MarshalledException(e);
   }
   } finally
      {
         Thread.currentThread().setContextClassLoader(oldCl);
      }
   }

   public Object invokeHome(Method m, Object[] args, Transaction tx,
    Principal identity, Object credential)
      throws Exception
   {
      // Check if this call really can be optimized
      // If parent of callers classloader is != parent of our classloader ->
not optimizable!
//      if (Thread.currentThread().getContextClassLoader().getParent() !=
container.getClassLoader().getParent())
      if
(!m.getDeclaringClass().isAssignableFrom(((ContainerInvokerContainer)contain
er).getHomeClass()))
      {
         RemoteMethodInvocation rmi = new RemoteMethodInvocation(null, m,
args);

         // Set the transaction context
         TransactionManager tm = container.getTransactionManager();
         rmi.setTransaction(tm != null? tm.getTransaction() : null);

         // Set the security stuff
         rmi.setPrincipal( SecurityAssociation.getPrincipal() );
         rmi.setCredential( SecurityAssociation.getCredential() );

         // Invoke on the container, enforce marshalling
   try
   {
          return invokeHome(new MarshalledObject(rmi)).get();
   }
   catch(MarshalledException e)
   {
    throw e.getOriginalException();
   }
      }

       // Set the right context classloader
       ClassLoader oldCl = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(container.getClassLoader());

       try
       {
          return container.invokeHome(new MethodInvocation(null , m, args,
tx,
                                         identity, credential));
       } finally
       {
          Thread.currentThread().setContextClassLoader(oldCl);
       }
   }

   public Object invoke(Object id, Method m, Object[] args, Transaction tx,
    Principal identity, Object credential )
      throws Exception
   {
    // Check if this call really can be optimized
    // If parent of callers classloader is != parent of our classloader ->
not optimizable!
//    if (Thread.currentThread().getContextClassLoader().getParent() !=
container.getClassLoader().getParent())
    if
(!m.getDeclaringClass().isAssignableFrom(((ContainerInvokerContainer)contain
er).getRemoteClass()))
    {
       RemoteMethodInvocation rmi = new RemoteMethodInvocation(id, m, args);

       // Set the transaction context
       TransactionManager tm = container.getTransactionManager();
       rmi.setTransaction(tm != null? tm.getTransaction() : null);

       // Set the security stuff
       rmi.setPrincipal( SecurityAssociation.getPrincipal() );
       rmi.setCredential( SecurityAssociation.getCredential() );

       // Invoke on the container, enforce marshalling
    try
    {
        return invoke(new MarshalledObject(rmi)).get();
    }
    catch(MarshalledException e)
    {
     throw e.getOriginalException();
    }
    }

       // Set the right context classloader
       ClassLoader oldCl = Thread.currentThread().getContextClassLoader();

Thread.currentThread().setContextClassLoader(container.getClassLoader());

       try
       {
          return container.invoke(new MethodInvocation(id, m, args, tx,
identity, credential));
       } finally
       {
          Thread.currentThread().setContextClassLoader(oldCl);
       }
   }

   // ContainerService implementation -------------------------------
   public void setContainer(Container con)
   {
      this.container = con;
      jndiName = container.getBeanMetaData().getJndiName();
   }

   public void init()
      throws Exception
   {
       // Set transaction manager
      GenericProxy.setTransactionManager(container.getTransactionManager());
      // Unfortunately this be a problem if many TM's are to be used
      // How to solve???

      // Create method mappings for container invoker
      Method[] methods =
((ContainerInvokerContainer)container).getRemoteClass().getMethods();
      beanMethodInvokerMap = new HashMap();
      for (int i = 0; i < methods.length; i++)
      {
         beanMethodInvokerMap.put(new
Integer(RemoteMethodInvocation.calculateHash(methods[i])), methods[i]);
      }

      methods =
((ContainerInvokerContainer)container).getHomeClass().getMethods();
      homeMethodInvokerMap = new HashMap();
      for (int i = 0; i < methods.length; i++)
      {
         homeMethodInvokerMap.put(new
Integer(RemoteMethodInvocation.calculateHash(methods[i])), methods[i]);
      }

      try {

        // Get the getEJBObjectMethod
        Method getEJBObjectMethod =
Class.forName("javax.ejb.Handle").getMethod("getEJBObject", new Class[0]);

        // Hash it
        homeMethodInvokerMap.put(new
Integer(RemoteMethodInvocation.calculateHash(getEJBObjectMethod)),getEJBObje
ctMethod);
      }
      catch (Exception e) {Logger.exception(e);}


      // Create metadata

      /**
         Constructor signature is

        public EJBMetaDataImpl(Class remote,
                        Class home,
                        Class pkClass,
                       boolean session,
                    boolean statelessSession,
                    HomeHandle homeHandle)
       */

      if (container.getBeanMetaData() instanceof EntityMetaData)
      {
         Class pkClass;
         EntityMetaData metaData =
(EntityMetaData)container.getBeanMetaData();
         String pkClassName = metaData.getPrimaryKeyClass();
         try {
         if(pkClassName != null)
            pkClass = container.getClassLoader().loadClass(pkClassName);
         else
            pkClass =
container.getClassLoader().loadClass(metaData.getEjbClass()).getField(metaDa
ta.getPrimKeyField()).getClass();
         } catch(NoSuchFieldException e) {
            Logger.error("Unable to identify Bean's Primary Key class!  Did
you specify a primary key class and/or field?  Does that field exist?");
            throw new RuntimeException("Primary Key Problem");
         } catch(NullPointerException e) {
            Logger.error("Unable to identify Bean's Primary Key class!  Did
you specify a primary key class and/or field?  Does that field exist?");
            throw new RuntimeException("Primary Key Problem");
         }
         ejbMetaData = new EJBMetaDataImpl(

((ContainerInvokerContainer)container).getRemoteClass(),

((ContainerInvokerContainer)container).getHomeClass(),
                           pkClass,
                           false, file://Session
                           false, file://Stateless
                           new HomeHandleImpl(jndiName));
      }
      else
      {
         if (((SessionMetaData)container.getBeanMetaData()).isStateless()) {

            ejbMetaData = new EJBMetaDataImpl(

((ContainerInvokerContainer)container).getRemoteClass(),

((ContainerInvokerContainer)container).getHomeClass(),
                           null, file://No PK
                           true, file://Session
                           true, file://Stateless
                           new HomeHandleImpl(jndiName));
         }
         // we are stateful
         else  {

            ejbMetaData = new EJBMetaDataImpl(

((ContainerInvokerContainer)container).getRemoteClass(),

((ContainerInvokerContainer)container).getHomeClass(),
                                        null, file://No PK
                                        true, file://Session
                                        false,//Stateless
                                        new HomeHandleImpl(jndiName));
        }
      }

   }

    public void start()
    throws Exception
    {
        try
        {
            /*         UnicastRemoteObject.exportObject(this,
            4444,
            new SecureSocketFactory(),
            new SecureSocketFactory());
            */

            if(unicastObjectPort == ANONYMOUS_PORT)
                UnicastRemoteObject.exportObject(this);
            else
                UnicastRemoteObject.exportObject(this,unicastObjectPort);
            GenericProxy.addLocal(container.getBeanMetaData().getJndiName(),
this);

            InitialContext context = new InitialContext();

            // Bind the home in the JNDI naming space
            rebind(
                // The context
                context,
                // Jndi name
                container.getBeanMetaData().getJndiName(),
                // The Home

((ContainerInvokerContainer)container).getContainerInvoker().getEJBHome());

            // Bind a bare bones invoker in the JNDI invoker naming space
            rebind(
                // The context
                context,
                // JNDI name under the invokers moniker
                "invokers/"+container.getBeanMetaData().getJndiName(),
                // The invoker

((ContainerInvokerContainer)container).getContainerInvoker());


            Logger.debug("Bound "+container.getBeanMetaData().getEjbName() +
" to " + container.getBeanMetaData().getJndiName());
        } catch (IOException e)
        {
            throw new ServerException("Could not bind either home or
invoker", e);
        }
    }

   public void stop()
   {
      try {
         InitialContext ctx = new InitialContext();
         ctx.unbind(container.getBeanMetaData().getJndiName());
         ctx.unbind("invokers/"+container.getBeanMetaData().getJndiName());

         UnicastRemoteObject.unexportObject(this, true);

      } catch (Exception e) {
         // ignore.
      }

      GenericProxy.removeLocal(container.getBeanMetaData().getJndiName());
   }

   public void destroy()
   {
   }

   // XmlLoadable implementation
   public void importXml(Element element) throws DeploymentException {
       String opt =
MetaData.getElementContent(MetaData.getUniqueChild(element, "Optimized"));
       optimize = Boolean.valueOf(opt).booleanValue();
       try {
          String port =
MetaData.getElementContent(MetaData.getUniqueChild(element,
"RMIObjectPort"));
          unicastObjectPort = Integer.parseInt(port);
       } catch(NumberFormatException e) {
          unicastObjectPort = ANONYMOUS_PORT;
       } catch(DeploymentException e) {
          unicastObjectPort = ANONYMOUS_PORT;
       }
       Logger.debug("Container Invoker RMI Port='"+(unicastObjectPort ==
ANONYMOUS_PORT ? "Anonymous" : Integer.toString(unicastObjectPort))+"'");
       Logger.debug("Container Invoker Optimize='"+optimize+"'");
   }


   // Package protected ---------------------------------------------

   // Protected -----------------------------------------------------
   protected void rebind(Context ctx, String name, Object val)
   throws NamingException
   {
    // Bind val to name in ctx, and make sure that all intermediate contexts
exist

    Name n = ctx.getNameParser("").parse(name);
    while (n.size() > 1)
    {
        String ctxName = n.get(0);
        try
        {
           ctx = (Context)ctx.lookup(ctxName);
        } catch (NameNotFoundException e)
        {
           ctx = ctx.createSubcontext(ctxName);
        }
        n = n.getSuffix(1);
    }

    ctx.rebind(n.get(0), val);
   }

   // Private -------------------------------------------------------

   // Inner classes -------------------------------------------------
}




--
--------------------------------------------------------------
To subscribe:        [EMAIL PROTECTED]
To unsubscribe:      [EMAIL PROTECTED]
List Help?:          [EMAIL PROTECTED]

Reply via email to