Defer unmarshalling UnknownExceptionInfo data
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 68b0832..5ae2c2c 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
@@ -591,6 +591,7 @@
                 } catch (InterruptedException ex) {
                 }
             }
+            if (ex_ instanceof UnresolvedException) ex_ = ((UnresolvedException)ex_).resolve();
             //
             // The downcall has completed
             //
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnection.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnection.java
index 966fed1..2280516 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnection.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnection.java
@@ -630,38 +630,7 @@
         if (ex instanceof UNKNOWN) {
             for (ServiceContext sc : scl) {
                 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, is._OB_codeConverters(), GIOP1_2)) {
-                        try {
-                            in.__setSendingContextRuntime(is.__getSendingContextRuntime());
-                            in.__setCodeBase(is.__getCodeBase());
-                            in._OB_readEndian();
-                            Throwable t = (Throwable) in.read_value();
-                            UnknownException x = new UnknownException(t);
-                            x.completed = ex.completed;
-                            x.minor = ex.minor;
-                            return x;
-                        } catch (Exception e) {
-                            final String dump = in.dumpData();
-                            final int curPos = in.buf_.pos();
-                            in.buf_.pos(0);
-                            final String fullDump = in.dumpData();
-                            in.buf_.pos(curPos);
-                            try (StringWriter sw = new StringWriter();
-                                    PrintWriter pw = new PrintWriter(sw)) {
-                                e.printStackTrace(pw);
-                                logger.severe(String.format("%s:%n%s:%n%s%n%s:%n%s%n%s:%n%s",
-                                        "Exception reading UnknownExceptionInfo service context",
-                                        "Remaining data", dump, "Full data", fullDump,
-                                        "Exception thrown", sw.toString()));
-                            }
-                        }
-                    } catch (IOException e) {
-                        //ignore IOException from AutoCloseable.close()
-                    }
-                    break;
+                    return new UnresolvedException((UNKNOWN) ex, sc.context_data, is);
                 }
             }
         }
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnectionThreaded.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnectionThreaded.java
index bc250df..c6d6c2e 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnectionThreaded.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/GIOPConnectionThreaded.java
@@ -378,7 +378,7 @@
             //
             try {
                 inMsg.extractHeader(buf);
-                logger.fine("Header received for message of size " + inMsg.size()); 
+                logger.fine("Header received for message of size " + inMsg.size());
                 buf.realloc(12 + inMsg.size());
             } catch (org.omg.CORBA.SystemException ex) {
                 processException(State.Error, ex, false);
@@ -718,7 +718,7 @@
         //
         try {
             boolean result = down.waitUntilCompleted(block);
-            logger.fine("Completed eceiving response with Downcall of type " + down.getClass().getName()); 
+            logger.fine("Completed receiving response with Downcall of type " + down.getClass().getName());
             return result; 
         } catch (org.omg.CORBA.SystemException ex) {
             processException(State.Closed, ex, false);
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/UnresolvedException.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/UnresolvedException.java
new file mode 100644
index 0000000..8d0aaf5
--- /dev/null
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/UnresolvedException.java
@@ -0,0 +1,82 @@
+package org.apache.yoko.orb.OB;
+
+import static org.apache.yoko.orb.OCI.GiopVersion.GIOP1_2;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.yoko.orb.CORBA.InputStream;
+import org.apache.yoko.orb.OCI.Buffer;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.portable.UnknownException;
+import org.omg.SendingContext.CodeBase;
+
+public class UnresolvedException extends UnknownException {
+    private static final Logger LOGGER = Logger.getLogger(UnresolvedException.class.getName());
+    private final UNKNOWN ex;
+    private final byte[] data;
+    private final CodeConverters converters;
+    private final CodeBase sendingContextRuntime;
+    private final String codebase;
+
+    UnresolvedException(UNKNOWN ex, byte[] data, InputStream is) {
+        super(ex);
+        super.completed = ex.completed;
+        super.minor = ex.minor;
+        this.ex = ex;
+        this.data = data;
+        this.converters = is._OB_codeConverters();
+        this.sendingContextRuntime = is.__getSendingContextRuntime();
+        this.codebase = is.__getCodeBase();
+    }
+
+    public SystemException resolve() {
+        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, converters, GIOP1_2)) {
+            if (LOGGER.isLoggable(Level.FINE))
+                LOGGER.fine(String.format("Unpacking Unknown Exception Info%n%s", in.dumpData()));
+            try {
+                in.__setSendingContextRuntime(sendingContextRuntime);
+                in.__setCodeBase(codebase);
+                in._OB_readEndian();
+                Throwable t = (Throwable) in.read_value();
+                UnknownException x = new UnknownException(t);
+                x.completed = ex.completed;
+                x.minor = ex.minor;
+                return x;
+            } catch (Exception e) {
+                final String dump = in.dumpData();
+                final int curPos = in.buf_.pos();
+                in.buf_.pos(0);
+                final String fullDump = in.dumpData();
+                in.buf_.pos(curPos);
+                try (StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw)) {
+                    e.printStackTrace(pw);
+                    LOGGER.severe(String.format("%s:%n%s:%n%s%n%s:%n%s%n%s:%n%s",
+                            "Exception reading UnknownExceptionInfo service context",
+                            "Remaining data", dump, "Full data", fullDump,
+                            "Exception thrown", sw.toString()));
+                }
+            }
+        } catch (IOException e) {
+            //ignore IOException from AutoCloseable.close()
+        }
+        return ex;
+    }
+
+    private void readObject(ObjectInputStream ois) throws IOException {
+        throw new NotSerializableException();
+    }
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        throw new NotSerializableException();
+    }
+}
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoLock.java b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoLock.java
index c9dea93..c2dbf5d 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoLock.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoLock.java
@@ -4,21 +4,48 @@
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 
-public class AutoLock implements AutoCloseable{
+public class AutoLock implements AutoCloseable {
     final AtomicReference<Lock> lockRef;
-    
+    final Lock downgradeLock;
+    final int downgradeHeld;
+
     AutoLock(Lock lock) {
+        this(lock, null, 0);
+    }
+
+    AutoLock(Lock lock, Lock downgradeLock, int downgradeHeld) {
         lockRef = new AtomicReference<>(lock);
+        this.downgradeLock = downgradeLock;
+        this.downgradeHeld = downgradeHeld;
+        for (int i = downgradeHeld; i > 0; i--) {
+            downgradeLock.unlock();
+        }
         lock.lock();
     }
-    
+
     @Override
     public void close() {
         Lock lock = lockRef.getAndSet(null);
-        if (lock != null) lock.unlock();
+        if (lock == null)
+            return;
+        for (int i = 0; i < downgradeHeld; i++) {
+            downgradeLock.lock();
+        }
+        lock.unlock();
     }
 
     public Condition newCondition() {
         return lockRef.get().newCondition();
     }
-}
\ No newline at end of file
+
+    public boolean downgrade() {
+        if (downgradeLock == null)
+            return false;
+        Lock oldLock = lockRef.getAndSet(downgradeLock);
+        if (oldLock == downgradeLock)
+            return false;
+        downgradeLock.lock();
+        oldLock.unlock();
+        return true;
+    }
+}
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoReadWriteLock.java b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoReadWriteLock.java
index f70c0a3..f9b47d0 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoReadWriteLock.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoReadWriteLock.java
@@ -1,16 +1,15 @@
 package org.apache.yoko.orb.util;
 
-import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 public class AutoReadWriteLock {
-    private final ReadWriteLock lock = new ReentrantReadWriteLock();
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
     
     public AutoLock getReadLock() {
         return new AutoLock(lock.readLock());
     }
 
     public AutoLock getWriteLock() {
-        return new AutoLock(lock.writeLock());
+        return new AutoLock(lock.writeLock(), lock.readLock(), lock.getReadHoldCount());
     }
-}
\ No newline at end of file
+}