He has the same approach (approximately) that Rickard was suggesting.

details:
Declare a marshalling wrapper exception.  Throw it from the marshalled
invoke and invokeHome methods.  Catch it in the calling methods and throw
the wrapped exception.

It is still necessary to catch and unwrap the exception in the other callers
(in interfaces):
2x HomeProxy
1x EntityProxy, StatelessSessionProxy, StatefulSessionProxy

He makes the marshalling exception an inner class of JRMPContainerInvoker.
Is that appropriate, since it needs to be used by callers from interfaces?
Or should it just be put in interfaces as an outer class?

Otherwise this seems like the right approach.  Appreciate comments, I am
happy to implement and test if no one else wants to.

ALSO:  ?????. in HomeProxy, line 186, we call the marshalled version of
invoke but do not unmarshall the result.  Here we are just calling remove
(in place of removeByPrimaryKey) so I don't know what kind of return value
we would be getting - maybe it will always be null and this is ok.  It
seemed strange though so I thought I would point it out.

-----Original Message-----
From: Carlo de Wolf [mailto:[EMAIL PROTECTED]] 
Sent: Tuesday, February 27, 2001 5:43 AM
To: jboss-user
Subject: [jBoss-User] UndeclaredThrowableException: problem solved


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]





---------------------------------------------------------------------
This message (including any attachments) contains confidential, proprietary
or privileged information intended for a specific purpose and individual(s),
and is protected by law.  If you receive this message in error, please
immediately delete it and all copies of it from your system, destroy any
hard copies of it and notify the sender.  Any unauthorized disclosure,
copying or distribution of any part of this message, or the taking of any
unauthorized action based on it, is strictly prohibited.

Reply via email to