Propagate unchecked exceptions in UnknownExceptionInfo service contexts
diff --git a/pom.xml b/pom.xml
index 304fa7c..cec4645 100644
--- a/pom.xml
+++ b/pom.xml
@@ -287,4 +287,11 @@
         <url>http://svn.apache.org/viewvc/geronimo/yoko/trunk</url>
     </scm>
 
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.servicemix.bundles</groupId>
+        <artifactId>org.apache.servicemix.bundles.bcel</artifactId>
+        <version>5.2_2</version>
+      </dependency>
+    </dependencies>
 </project>
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/Downcall.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/Downcall.java
index 541a63c..eef3adb 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/Downcall.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/Downcall.java
@@ -17,7 +17,15 @@
 
 package org.apache.yoko.orb.OB;
 
-import java.util.logging.Level;
+import java.util.Vector;
+
+import org.apache.yoko.orb.OCI.Buffer;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.portable.UnknownException;
+import org.omg.IOP.ServiceContext;
+import org.omg.IOP.UnknownExceptionInfo;
 
 public class Downcall {
     //
@@ -118,9 +126,9 @@
     //
     // The request and reply service contexts
     //
-    protected java.util.Vector requestSCL_ = new java.util.Vector();
+    protected Vector<ServiceContext> requestSCL_ = new Vector<>();
 
-    protected java.util.Vector replySCL_ = new java.util.Vector();
+    protected Vector<ServiceContext> replySCL_ = new Vector<>();
 
     // ----------------------------------------------------------------------
     // Downcall private and protected member implementations
@@ -547,10 +555,32 @@
         Assert._OB_assert(responseExpected_);
         Assert._OB_assert(ex_ == null);
         state_ = DowncallStateSystemException;
-        ex_ = ex;
+        ex_ = convertToUnknownExceptionIfAppropriate(ex);
         logger_.debug("Received system exception", ex);
     }
 
+    private SystemException convertToUnknownExceptionIfAppropriate(org.omg.CORBA.SystemException ex) {
+        if (ex instanceof UNKNOWN) {
+            for (ServiceContext sc : replySCL_) {
+                if (sc.context_id == UnknownExceptionInfo.value) {
+                    final byte[] data = sc.context_data;
+                    Buffer buf = new Buffer(data, data.length);
+                    try (org.apache.yoko.orb.CORBA.InputStream in =
+                            new org.apache.yoko.orb.CORBA.InputStream(buf, 0, false)) {
+                        Throwable t = (Throwable) in.read_value();
+                        UnknownException x = new UnknownException(t);
+                        x.completed = ex.completed;
+                        x.minor = ex.minor;
+                        return x;
+                    } catch (Exception e) {
+                        throw (MARSHAL)(new MARSHAL(e.getMessage())).initCause(e);
+                    }
+                }
+            }
+        }
+        return ex;
+    }
+
     public void setSystemException(org.omg.CORBA.SystemException ex) {
         if (stateMonitor_ != null) {
             synchronized (stateMonitor_) {
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/Upcall.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/Upcall.java
index 9ffb3a7..3f2e343 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/Upcall.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/Upcall.java
@@ -17,11 +17,20 @@
 
 package org.apache.yoko.orb.OB;
 
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Vector;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.apache.yoko.orb.CORBA.OutputStream;
 import org.apache.yoko.orb.OB.DispatchRequest;
 import org.apache.yoko.orb.OB.DispatchStrategy;
+import org.apache.yoko.orb.OCI.Buffer;
+import org.omg.CORBA.INTERNAL;
+import org.omg.CORBA.portable.UnknownException;
+import org.omg.IOP.ServiceContext;
+import org.omg.IOP.UnknownExceptionInfo;
 
 public class Upcall {
     static final Logger logger = Logger.getLogger(Upcall.class.getName());
@@ -76,7 +85,7 @@
     // The reply service context list
     // (Must be a Vector because it can be modified by interceptors)
     //
-    protected java.util.Vector replySCL_ = new java.util.Vector();
+    protected Vector<ServiceContext> replySCL_ = new Vector<>();
 
     //
     // The dispatch request
@@ -294,8 +303,24 @@
         // OutputStream to make the skeleton happy and avoid a crash.
         //
         if (upcallReturn_ != null) {
-            if (!upcallReturn_.replySent() && (profileInfo_.major > 1 || profileInfo_.minor >= 1)) {
-                initServiceContexts();
+            addUnsentConnectionServiceContexts();
+            org.omg.IOP.ServiceContext[] scl = new org.omg.IOP.ServiceContext[replySCL_
+                    .size()];
+            replySCL_.copyInto(scl);
+            upcallReturn_.upcallBeginReply(this, scl);
+        } else {
+            org.apache.yoko.orb.OCI.Buffer buf = new org.apache.yoko.orb.OCI.Buffer();
+            out_ = new org.apache.yoko.orb.CORBA.OutputStream(buf, in_
+                    ._OB_codeConverters(), (profileInfo_.major << 8)
+                    | profileInfo_.minor);
+        }
+        out_._OB_ORBInstance(this.orbInstance());
+        return out_;
+    }
+
+    private void addUnsentConnectionServiceContexts() {
+        if (!upcallReturn_.replySent() && (profileInfo_.major > 1 || profileInfo_.minor >= 1)) {
+            initServiceContexts();
 //                CoreTraceLevels coreTraceLevels = orbInstance_
 //                        .getCoreTraceLevels();
 //                if (coreTraceLevels.traceConnections() >= 2) {
@@ -323,21 +348,9 @@
 //                Assert._OB_assert(codeSetSC_ != null);
 //                replySCL_.add(codeSetSC_);
 
-                Assert._OB_assert(codeBaseSC_ != null);
-                replySCL_.add(codeBaseSC_);
-            }
-            org.omg.IOP.ServiceContext[] scl = new org.omg.IOP.ServiceContext[replySCL_
-                    .size()];
-            replySCL_.copyInto(scl);
-            upcallReturn_.upcallBeginReply(this, scl);
-        } else {
-            org.apache.yoko.orb.OCI.Buffer buf = new org.apache.yoko.orb.OCI.Buffer();
-            out_ = new org.apache.yoko.orb.CORBA.OutputStream(buf, in_
-                    ._OB_codeConverters(), (profileInfo_.major << 8)
-                    | profileInfo_.minor);
+            Assert._OB_assert(codeBaseSC_ != null);
+            replySCL_.add(codeBaseSC_);
         }
-        out_._OB_ORBInstance(this.orbInstance());
-        return out_;
     }
 
     public void marshalEx(org.omg.CORBA.SystemException ex)
@@ -423,14 +436,30 @@
 
     public void setSystemException(org.omg.CORBA.SystemException ex) {
         if (upcallReturn_ != null) {
-            userEx_ = false; // Java only
-            org.omg.IOP.ServiceContext[] scl = new org.omg.IOP.ServiceContext[replySCL_
-                    .size()];
+            addUnsentConnectionServiceContexts();
+            userEx_ = false;
+            if (ex instanceof UnknownException) {
+                // need to create an exception info service context
+                replySCL_.add(createUnknownExceptionInfoServiceContext((UnknownException)ex));
+            }
+            ServiceContext[] scl = new ServiceContext[replySCL_.size()];
             replySCL_.copyInto(scl);
             upcallReturn_.upcallSystemException(this, ex, scl);
         }
     }
 
+    private static ServiceContext createUnknownExceptionInfoServiceContext(UnknownException ex) {
+        Throwable t = ex.originalEx;
+        Buffer buf = new Buffer();
+        try (OutputStream os = new OutputStream(buf)) {
+            os.write_value(t, Throwable.class);
+            ServiceContext sc = new ServiceContext(UnknownExceptionInfo.value, Arrays.copyOf(buf.data(), buf.length()));
+            return sc;
+        } catch (IOException e) {
+            throw (INTERNAL)(new INTERNAL(e.getMessage())).initCause(e);
+        }
+    }
+
     public void setLocationForward(org.omg.IOP.IOR ior, boolean perm) {
         if (upcallReturn_ != null) {
             userEx_ = false; // Java only
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java
index bf05680..bcaf2aa 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/ValueReader.java
@@ -269,6 +269,9 @@
         }
 
         private BoxedValueHelper getBoxedHelper(String id) {
+            if (WStringValueHelper.id().equals(id))
+                return new WStringValueHelper();
+
             final Class helperClass = Util.idToClass(id, "Helper");
 
             if (helperClass != null) {
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/cmsf/CmsfVersion.java b/yoko-core/src/main/java/org/apache/yoko/orb/cmsf/CmsfVersion.java
index b8bc632..552c942 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/cmsf/CmsfVersion.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/cmsf/CmsfVersion.java
@@ -1,6 +1,7 @@
 package org.apache.yoko.orb.cmsf;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 import org.apache.yoko.orb.OCI.Buffer;
 import org.omg.CORBA.Any;
@@ -69,12 +70,12 @@
     }
     
     private static byte[] genData(byte value) {
-        Buffer buf = new Buffer();
+        Buffer buf = new Buffer(2);
         try (org.apache.yoko.orb.CORBA.OutputStream out = 
                 new org.apache.yoko.orb.CORBA.OutputStream(buf)) {
             out._OB_writeEndian();
             out.write_octet(value);
-            return buf.data();
+            return Arrays.copyOf(buf.data(), buf.length());
         } catch (IOException e) {
             throw (INTERNAL)(new INTERNAL(e.getMessage())).initCause(e);
         }
diff --git a/yoko-core/src/test/java/org/apache/yoko/RMIExceptionHandlingTest.java b/yoko-core/src/test/java/org/apache/yoko/RMIExceptionHandlingTest.java
new file mode 100644
index 0000000..17e8916
--- /dev/null
+++ b/yoko-core/src/test/java/org/apache/yoko/RMIExceptionHandlingTest.java
@@ -0,0 +1,86 @@
+package org.apache.yoko;
+
+import java.rmi.RemoteException;
+import java.util.Properties;
+
+import javax.rmi.PortableRemoteObject;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.omg.CORBA.ORB;
+import org.omg.PortableServer.POA;
+import org.omg.PortableServer.POAHelper;
+
+import test.rmi.exceptionhandling.MyAppException;
+import test.rmi.exceptionhandling.MyClientRequestInterceptor;
+import test.rmi.exceptionhandling.MyRuntimeException;
+import test.rmi.exceptionhandling.MyServerRequestInterceptor;
+import test.rmi.exceptionhandling.Thrower;
+import test.rmi.exceptionhandling.ThrowerImpl;
+import test.rmi.exceptionhandling._ThrowerImpl_Tie;
+
+@SuppressWarnings("serial")
+public class RMIExceptionHandlingTest {
+    private static ORB serverOrb;
+    private static ORB clientOrb;
+    private static String ior;
+
+    private static ORB initOrb(Properties props, String... args) {
+        return ORB.init(args, props);
+    }
+
+    @BeforeClass
+    public static void createServerORB() throws Exception {
+        serverOrb = initOrb(new Properties() {{
+            put("org.omg.PortableInterceptor.ORBInitializerClass." + MyClientRequestInterceptor.class.getName(),"");
+            put("org.omg.PortableInterceptor.ORBInitializerClass." + MyServerRequestInterceptor.class.getName(),"");
+        }});
+        POA poa = POAHelper.narrow(serverOrb.resolve_initial_references("RootPOA"));
+        poa.the_POAManager().activate();
+
+        _ThrowerImpl_Tie tie = new _ThrowerImpl_Tie();
+        tie.setTarget(new ThrowerImpl());
+
+        poa.activate_object(tie);
+        ior = serverOrb.object_to_string(tie.thisObject());
+        System.out.println(ior);
+    }
+
+    @BeforeClass
+    public static void createClientORB() {
+        clientOrb = initOrb(new Properties() {{
+            put("org.omg.PortableInterceptor.ORBInitializerClass." + MyClientRequestInterceptor.class.getName(),"");
+        }});
+    }
+
+    @AfterClass
+    public static void shutdownServerORB() {
+        serverOrb.shutdown(true);
+        serverOrb.destroy();
+        ior = null;
+    }
+
+    @AfterClass
+    public static void shutdownClientORB() {
+        clientOrb.shutdown(true);
+        clientOrb.destroy();
+    }
+
+    @Test(expected=MyRuntimeException.class)
+    public void testRuntimeException() throws RemoteException {
+        getThrower(clientOrb).throwRuntimeException();
+    }
+
+    @Test(expected=MyAppException.class)
+    public void testAppException() throws RemoteException, MyAppException {
+        getThrower(clientOrb).throwAppException();
+    }
+
+    private Thrower getThrower(ORB orb) {
+        Object o = orb.string_to_object(ior);
+        Thrower thrower = (Thrower) PortableRemoteObject.narrow(o, Thrower.class);
+        return thrower;
+    }
+}
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/MyAppException.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyAppException.java
new file mode 100644
index 0000000..662705b
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyAppException.java
@@ -0,0 +1,3 @@
+package test.rmi.exceptionhandling;
+
+public class MyAppException extends Exception {}
\ No newline at end of file
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/MyClientRequestInterceptor.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyClientRequestInterceptor.java
new file mode 100644
index 0000000..1f05ee5
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyClientRequestInterceptor.java
@@ -0,0 +1,64 @@
+package test.rmi.exceptionhandling;
+
+import org.omg.CORBA.LocalObject;
+import org.omg.PortableInterceptor.ClientRequestInfo;
+import org.omg.PortableInterceptor.ClientRequestInterceptor;
+import org.omg.PortableInterceptor.ForwardRequest;
+import org.omg.PortableInterceptor.ORBInitInfo;
+import org.omg.PortableInterceptor.ORBInitializer;
+import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
+
+public class MyClientRequestInterceptor extends LocalObject implements ClientRequestInterceptor, ORBInitializer {
+
+    @Override
+    public void receive_exception(ClientRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("receive_exception(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void receive_other(ClientRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("receive_other(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void receive_reply(ClientRequestInfo arg0) {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("receive_reply(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void send_poll(ClientRequestInfo arg0) {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("send_poll(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void send_request(ClientRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("send_request(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public String name() {
+        return this.getClass().getName();
+    }
+
+    @Override
+    public void post_init(ORBInitInfo arg0) {
+        try {
+            arg0.add_client_request_interceptor(this);
+        } catch (DuplicateName e) {
+            throw new Error(e);
+        }
+    }
+
+    @Override
+    public void pre_init(ORBInitInfo arg0) {
+    }
+}
\ No newline at end of file
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/MyRuntimeException.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyRuntimeException.java
new file mode 100644
index 0000000..cf1de8c
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyRuntimeException.java
@@ -0,0 +1,3 @@
+package test.rmi.exceptionhandling;
+
+public class MyRuntimeException extends RuntimeException {}
\ No newline at end of file
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/MyServerRequestInterceptor.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyServerRequestInterceptor.java
new file mode 100644
index 0000000..56ceaaf
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/MyServerRequestInterceptor.java
@@ -0,0 +1,64 @@
+package test.rmi.exceptionhandling;
+
+import org.omg.CORBA.LocalObject;
+import org.omg.PortableInterceptor.ForwardRequest;
+import org.omg.PortableInterceptor.ORBInitInfo;
+import org.omg.PortableInterceptor.ORBInitializer;
+import org.omg.PortableInterceptor.ServerRequestInfo;
+import org.omg.PortableInterceptor.ServerRequestInterceptor;
+import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
+
+public class MyServerRequestInterceptor extends LocalObject implements ServerRequestInterceptor, ORBInitializer {
+
+    @Override
+    public void receive_request(ServerRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("receive_request(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void receive_request_service_contexts(ServerRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("receive_request_service_contexts(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void send_exception(ServerRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("send_exception(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void send_other(ServerRequestInfo arg0) throws ForwardRequest {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("send_other(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void send_reply(ServerRequestInfo arg0) {
+        System.out.printf("%08x: ", Thread.currentThread().getId());
+        System.out.println("send_reply(" + arg0.operation() + ")");
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public String name() {
+        return this.getClass().getName();
+    }
+
+    @Override
+    public void post_init(ORBInitInfo arg0) {
+        try {
+            arg0.add_server_request_interceptor(this);
+        } catch (DuplicateName e) {
+            throw new Error(e);
+        }
+    }
+
+    @Override
+    public void pre_init(ORBInitInfo arg0) {
+    }
+}
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/Thrower.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/Thrower.java
new file mode 100644
index 0000000..b8b9a02
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/Thrower.java
@@ -0,0 +1,9 @@
+package test.rmi.exceptionhandling;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+public interface Thrower extends Remote {
+    void throwAppException() throws RemoteException, MyAppException;
+    void throwRuntimeException() throws RemoteException;
+}
\ No newline at end of file
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/ThrowerImpl.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/ThrowerImpl.java
new file mode 100644
index 0000000..63c1cb8
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/ThrowerImpl.java
@@ -0,0 +1,15 @@
+package test.rmi.exceptionhandling;
+
+import java.rmi.RemoteException;
+
+public class ThrowerImpl implements Thrower {
+    @Override
+    public void throwAppException() throws RemoteException, MyAppException {
+        throw new MyAppException();
+    }
+
+    @Override
+    public void throwRuntimeException() throws RemoteException {
+        throw new MyRuntimeException();
+    }
+}
\ No newline at end of file
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/_ThrowerImpl_Tie.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/_ThrowerImpl_Tie.java
new file mode 100644
index 0000000..434e16a
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/_ThrowerImpl_Tie.java
@@ -0,0 +1,113 @@
+// POA Tie class generated by rmic, do not edit.
+// Contents subject to change without notice.
+
+package test.rmi.exceptionhandling;
+
+import java.lang.ClassCastException;
+import java.lang.String;
+import java.lang.Throwable;
+import java.rmi.Remote;
+import javax.rmi.CORBA.Tie;
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ResponseHandler;
+import org.omg.CORBA.portable.UnknownException;
+import org.omg.PortableServer.POA;
+import org.omg.PortableServer.POAPackage.ObjectNotActive;
+import org.omg.PortableServer.POAPackage.ServantNotActive;
+import org.omg.PortableServer.POAPackage.WrongPolicy;
+
+public class _ThrowerImpl_Tie extends org.omg.PortableServer.Servant implements Tie {
+    
+    private ThrowerImpl target = null;
+    
+    private static final String[] _type_ids = {
+        "RMI:test.rmi.exceptionhandling.Thrower:0000000000000000"
+    };
+    
+    public void setTarget(Remote target) {
+        this.target = (ThrowerImpl) target;
+    }
+    
+    public Remote getTarget() {
+        return target;
+    }
+    
+    public Object thisObject() {
+        return _this_object();
+    }
+    
+    public void deactivate() {
+        try {
+            _poa().deactivate_object(_poa().servant_to_id(this));
+        }
+        catch(WrongPolicy e) { }
+        catch(ObjectNotActive e) { }
+        catch(ServantNotActive e) { }
+    }
+    
+    public ORB orb() {
+        return _orb();
+    }
+    
+    public void orb(ORB orb) {
+        try {
+            ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this);
+        }
+        catch(ClassCastException e) {
+            throw new BAD_PARAM("POA Servant needs an org.omg.CORBA_2_3.ORB");
+        }
+    }
+    
+    public String[] _all_interfaces(POA poa, byte[] objectId) { 
+        return (String [] )  _type_ids.clone();
+    }
+    
+    public OutputStream _invoke(String method, InputStream _in, ResponseHandler reply) throws SystemException {
+        try {
+            org.omg.CORBA_2_3.portable.InputStream in = 
+                (org.omg.CORBA_2_3.portable.InputStream) _in;
+            switch (method.length()) {
+                case 17: 
+                    if (method.equals("throwAppException")) {
+                        return throwAppException(in, reply);
+                    }
+                case 21: 
+                    if (method.equals("throwRuntimeException")) {
+                        return throwRuntimeException(in, reply);
+                    }
+            }
+            throw new BAD_OPERATION();
+        } catch (SystemException ex) {
+            throw ex;
+        } catch (Throwable ex) {
+            throw new UnknownException(ex);
+        }
+    }
+    
+    private OutputStream throwAppException(org.omg.CORBA_2_3.portable.InputStream in , ResponseHandler reply) throws Throwable {
+        try {
+            target.throwAppException();
+        } catch (MyAppException ex) {
+            String id = "IDL:test/rmi/exceptionhandling/MyAppEx:1.0";
+            org.omg.CORBA_2_3.portable.OutputStream out = 
+                (org.omg.CORBA_2_3.portable.OutputStream) reply.createExceptionReply();
+            out.write_string(id);
+            out.write_value(ex,MyAppException.class);
+            return out;
+        }
+        OutputStream out = reply.createReply();
+        return out;
+    }
+    
+    private OutputStream throwRuntimeException(org.omg.CORBA_2_3.portable.InputStream in , ResponseHandler reply) throws Throwable {
+        target.throwRuntimeException();
+        OutputStream out = reply.createReply();
+        return out;
+    }
+}
diff --git a/yoko-core/src/test/java/test/rmi/exceptionhandling/_Thrower_Stub.java b/yoko-core/src/test/java/test/rmi/exceptionhandling/_Thrower_Stub.java
new file mode 100644
index 0000000..884897e
--- /dev/null
+++ b/yoko-core/src/test/java/test/rmi/exceptionhandling/_Thrower_Stub.java
@@ -0,0 +1,112 @@
+// Stub class generated by rmic, do not edit.
+// Contents subject to change without notice.
+
+package test.rmi.exceptionhandling;
+
+import java.lang.String;
+import java.lang.Throwable;
+import java.rmi.RemoteException;
+import java.rmi.UnexpectedException;
+import javax.rmi.CORBA.Stub;
+import javax.rmi.CORBA.Util;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.portable.ApplicationException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.RemarshalException;
+import org.omg.CORBA.portable.ServantObject;
+
+public class _Thrower_Stub extends Stub implements Thrower {
+    
+    private static final String[] _type_ids = {
+        "RMI:test.rmi.exceptionhandling.Thrower:0000000000000000"
+    };
+    
+    public String[] _ids() { 
+        return (String [] )  _type_ids.clone();
+    }
+    
+    public void throwAppException() throws RemoteException, MyAppException {
+        while(true) {
+            if (!Util.isLocal(this)) {
+                org.omg.CORBA_2_3.portable.InputStream in = null;
+                try {
+                    try {
+                        OutputStream out = _request("throwAppException", true);
+                        _invoke(out);
+                        return;
+                    } catch (ApplicationException ex) {
+                        in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream();
+                        String id = in.read_string();
+                        if (id.equals("IDL:test/rmi/exceptionhandling/MyAppEx:1.0")) {
+                            throw (MyAppException) in.read_value(MyAppException.class);
+                        }
+                        throw new UnexpectedException(id);
+                    } catch (RemarshalException ex) {
+                        continue;
+                    }
+                } catch (SystemException ex) {
+                    throw Util.mapSystemException(ex);
+                } finally {
+                    _releaseReply(in);
+                }
+            } else {
+                ServantObject so = _servant_preinvoke("throwAppException",test.rmi.exceptionhandling.Thrower.class);
+                if (so == null) {
+                    continue;
+                }
+                try {
+                    ((test.rmi.exceptionhandling.Thrower)so.servant).throwAppException();
+                    return;
+                } catch (Throwable ex) {
+                    Throwable exCopy = (Throwable)Util.copyObject(ex,_orb());
+                    if (exCopy instanceof MyAppException) {
+                        throw (MyAppException)exCopy;
+                    }
+                    throw Util.wrapException(exCopy);
+                } finally {
+                    _servant_postinvoke(so);
+                }
+            }
+        }
+    }
+    
+    public void throwRuntimeException() throws RemoteException {
+        while(true) {
+            if (!Util.isLocal(this)) {
+                InputStream in = null;
+                try {
+                    try {
+                        OutputStream out = _request("throwRuntimeException", true);
+                        _invoke(out);
+                        return;
+                    } catch (ApplicationException ex) {
+                        in = ex.getInputStream();
+                        String id = in.read_string();
+                        throw new UnexpectedException(id);
+                    } catch (RemarshalException ex) {
+                        continue;
+                    }
+                } catch (SystemException ex) {
+                    throw Util.mapSystemException(ex);
+                } finally {
+                    _releaseReply(in);
+                }
+            } else {
+                ServantObject so = _servant_preinvoke("throwRuntimeException",test.rmi.exceptionhandling.Thrower.class);
+                if (so == null) {
+                    continue;
+                }
+                try {
+                    ((test.rmi.exceptionhandling.Thrower)so.servant).throwRuntimeException();
+                    return;
+                } catch (Throwable ex) {
+                    Throwable exCopy = (Throwable)Util.copyObject(ex,_orb());
+                    throw Util.wrapException(exCopy);
+                } finally {
+                    _servant_postinvoke(so);
+                }
+            }
+        }
+    }
+}