Merge branch 'ibm-trunk' into ueinfo_with_downcall_locking
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OB/CollocatedServer.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/CollocatedServer.java
index bd3ac2a..78c0e74 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/CollocatedServer.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/CollocatedServer.java
@@ -146,7 +146,7 @@
         // dispatch thread is used, we could avoid initializing the
         // state monitor when it is not needed.
         //
-        down.initStateMonitor();
+        down.allowWaiting();
 
         Upcall up;
 
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 cda88f5..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
@@ -17,19 +17,16 @@
 
 package org.apache.yoko.orb.OB;
 
-import static org.apache.yoko.orb.OB.CodeSetDatabase.UTF16;
-import static org.apache.yoko.orb.OCI.GiopVersion.GIOP1_2;
-
 import java.util.Vector;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
 
-import org.apache.yoko.orb.OCI.Buffer;
 import org.apache.yoko.orb.OCI.GiopVersion;
-import org.omg.CORBA.MARSHAL;
-import org.omg.CORBA.SystemException;
-import org.omg.CORBA.UNKNOWN;
-import org.omg.CORBA.portable.UnknownException;
+import org.apache.yoko.orb.util.AutoLock;
+import org.apache.yoko.orb.util.AutoReadWriteLock;
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.NO_RESPONSE;
 import org.omg.IOP.ServiceContext;
-import org.omg.IOP.UnknownExceptionInfo;
 
 public class Downcall {
     //
@@ -87,25 +84,13 @@
     //
     // The state of this invocation
     //
-    protected static final int DowncallStateUnsent = 0;
-
-    protected static final int DowncallStatePending = 1;
-
-    protected static final int DowncallStateNoException = 2;
-
-    protected static final int DowncallStateUserException = 3;
-
-    protected static final int DowncallStateSystemException = 4;
-
-    protected static final int DowncallStateFailureException = 5;
-
-    protected static final int DowncallStateForward = 6;
-
-    protected static final int DowncallStateForwardPerm = 7;
-
-    protected int state_;
-
-    protected java.lang.Object stateMonitor_;
+    protected enum State { UNSENT, PENDING, NO_EXCEPTION, USER_EXCEPTION, SYSTEM_EXCEPTION, FAILURE_EXCEPTION, FORWARD, FORWARD_PERM }
+    
+    protected final AutoReadWriteLock stateLock = new AutoReadWriteLock();
+    
+    protected State state = State.UNSENT;
+    
+    protected Condition stateWaitCondition;
 
     //
     // Holds the exception if state_ is DowncallStateUserException,
@@ -142,36 +127,38 @@
     // Raise an exception if necessary
     //
     void checkForException() throws LocationForward, FailureException {
-        switch (state_) {
-        case DowncallStateUserException:
-            //
-            // Do not raise UserException in Java
-            //
-            // if(ex_ != null) // Only raise if a user exception has been set
-            // throw ex_;
-            break;
+        try (AutoLock readLock = stateLock.getReadLock()) {
+            switch (state) {
+                case USER_EXCEPTION:
+                    //
+                    // Do not raise UserException in Java
+                    //
+                    // if(ex_ != null) // Only raise if a user exception has been set
+                    // throw ex_;
+                    break;
 
-        case DowncallStateSystemException:
-            Assert._OB_assert(ex_ != null);
-            // update the stack trace to have the caller's stack rather than the 
-            // receiver thread. 
-            ex_.fillInStackTrace();    
-            throw (org.omg.CORBA.SystemException) ex_;
+                case SYSTEM_EXCEPTION:
+                    Assert._OB_assert(ex_ != null);
+                    // update the stack trace to have the caller's stack rather than the 
+                    // receiver thread. 
+                    ex_.fillInStackTrace();    
+                    throw (org.omg.CORBA.SystemException) ex_;
 
-        case DowncallStateFailureException:
-            Assert._OB_assert(ex_ != null);
-            throw new FailureException((org.omg.CORBA.SystemException) ex_);
+                case FAILURE_EXCEPTION:
+                    Assert._OB_assert(ex_ != null);
+                    throw new FailureException((org.omg.CORBA.SystemException) ex_);
 
-        case DowncallStateForward:
-            Assert._OB_assert(forwardIOR_ != null);
-            throw new LocationForward(forwardIOR_, false);
+                case FORWARD:
+                    Assert._OB_assert(forwardIOR_ != null);
+                    throw new LocationForward(forwardIOR_, false);
 
-        case DowncallStateForwardPerm:
-            Assert._OB_assert(forwardIOR_ != null);
-            throw new LocationForward(forwardIOR_, true);
+                case FORWARD_PERM:
+                    Assert._OB_assert(forwardIOR_ != null);
+                    throw new LocationForward(forwardIOR_, true);
 
-        default:
-            break;
+                default:
+                    break;
+            }
         }
     }
 
@@ -203,8 +190,10 @@
         policies_ = policies;
         op_ = op;
         responseExpected_ = resp;
-        state_ = DowncallStateUnsent;
-        stateMonitor_ = null;
+        // since this.state is not volatile we must use a lock to guarantee consistency
+        try (AutoLock writeLock = stateLock.getWriteLock()) {
+            state = State.UNSENT;
+        }
         ex_ = null;
 
         //
@@ -215,58 +204,58 @@
         logger_.debug("Downcall created for operation " + op + " with id " + reqId_); 
     }
 
-    public ORBInstance orbInstance() {
+    public final ORBInstance orbInstance() {
         return orbInstance_;
     }
 
-    public Client client() {
+    public final Client client() {
         return client_;
     }
 
-    public org.apache.yoko.orb.OCI.ProfileInfo profileInfo() {
+    public final org.apache.yoko.orb.OCI.ProfileInfo profileInfo() {
         return profileInfo_;
     }
 
-    public RefCountPolicyList policies() {
+    public final RefCountPolicyList policies() {
         return policies_;
     }
 
-    public Exception excep() {
+    public final Exception excep() {
         return ex_;
     }
 
-    public int requestId() {
+    public final int requestId() {
         return reqId_;
     }
 
-    public String operation() {
+    public final String operation() {
         return op_;
     }
 
-    public boolean responseExpected() {
+    public final boolean responseExpected() {
         return responseExpected_;
     }
 
-    public org.apache.yoko.orb.CORBA.OutputStream output() {
+    public final org.apache.yoko.orb.CORBA.OutputStream output() {
         return out_;
     }
 
-    public org.apache.yoko.orb.CORBA.InputStream input() {
+    public final org.apache.yoko.orb.CORBA.InputStream input() {
         return in_;
     }
 
-    public org.omg.IOP.ServiceContext[] getRequestSCL() {
+    public final org.omg.IOP.ServiceContext[] getRequestSCL() {
         org.omg.IOP.ServiceContext[] scl = new org.omg.IOP.ServiceContext[requestSCL_
                 .size()];
         requestSCL_.copyInto(scl);
         return scl;
     }
 
-    public void addToRequestSCL(org.omg.IOP.ServiceContext sc) {
+    public final void addToRequestSCL(org.omg.IOP.ServiceContext sc) {
         requestSCL_.addElement(sc);
     }
 
-    public void setReplySCL(org.omg.IOP.ServiceContext[] scl) {
+    public final void setReplySCL(org.omg.IOP.ServiceContext[] scl) {
         // Don't create a new Vector
         Assert._OB_assert(replySCL_.size() == 0);
         replySCL_.setSize(scl.length);
@@ -279,17 +268,17 @@
         return preMarshalBase();
     }
 
-    public void marshalEx(org.omg.CORBA.SystemException ex)
+    public final void marshalEx(org.omg.CORBA.SystemException ex)
             throws LocationForward, FailureException {
         setFailureException(ex);
         checkForException();
         Assert._OB_assert(false);
     }
 
-    public void postMarshal() throws LocationForward, FailureException {
+    public final void postMarshal() throws LocationForward, FailureException {
     }
 
-    public void locate() throws LocationForward, FailureException {
+    public final void locate() throws LocationForward, FailureException {
         Assert._OB_assert(responseExpected_);
         Assert._OB_assert(op_.equals("_locate"));
 
@@ -311,7 +300,7 @@
         checkForException();
     }
 
-    public void request() throws LocationForward, FailureException {
+    public final void request() throws LocationForward, FailureException {
         Assert._OB_assert(responseExpected_);
 
         //
@@ -331,7 +320,7 @@
         checkForException();
     }
 
-    public void oneway() throws LocationForward, FailureException {
+    public final void oneway() throws LocationForward, FailureException {
         Assert._OB_assert(!responseExpected_);
 
         if (policies_.syncScope == org.omg.Messaging.SYNC_WITH_TRANSPORT.value) {
@@ -345,7 +334,7 @@
         }
     }
 
-    public void deferred() throws LocationForward, FailureException {
+    public final void deferred() throws LocationForward, FailureException {
         Assert._OB_assert(responseExpected_);
 
         boolean finished = emitter_.send(this, true);
@@ -353,7 +342,7 @@
             checkForException();
     }
 
-    public void response() throws LocationForward, FailureException {
+    public final void response() throws LocationForward, FailureException {
         Assert._OB_assert(responseExpected_);
 
         boolean finished = emitter_.receive(this, true);
@@ -361,23 +350,25 @@
         checkForException();
     }
 
-    public boolean poll() throws LocationForward, FailureException {
+    public final boolean poll() throws LocationForward, FailureException {
         Assert._OB_assert(responseExpected_);
 
         boolean finished = emitter_.receive(this, false);
         if (finished) {
-            checkForException();
-            return state_ != DowncallStatePending;
+            try (AutoLock lock = stateLock.getReadLock()) {
+                checkForException();
+                return state != State.PENDING;
+            }
         } else
             return false;
     }
 
-    public org.apache.yoko.orb.CORBA.InputStream preUnmarshal()
+    public final org.apache.yoko.orb.CORBA.InputStream preUnmarshal()
             throws LocationForward, FailureException {
         return in_;
     }
 
-    public void unmarshalEx(org.omg.CORBA.SystemException ex)
+    public final void unmarshalEx(org.omg.CORBA.SystemException ex)
             throws LocationForward, FailureException {
         setFailureException(ex);
         checkForException();
@@ -394,314 +385,213 @@
         // the user exception, so we only want to raise UNKNOWN if we
         // don't have the ID
         //
-        if (state_ == DowncallStateUserException && ex_ == null
-                && exId_ == null)
-            setSystemException(new org.omg.CORBA.UNKNOWN(org.apache.yoko.orb.OB.MinorCodes
-                    .describeUnknown(org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException),
-                    org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
-                    org.omg.CORBA.CompletionStatus.COMPLETED_YES));
-
-        checkForException();
+        try (AutoLock lock = stateLock.getReadLock()) {
+            if (state == State.USER_EXCEPTION && ex_ == null && exId_ == null)
+                setSystemException(new org.omg.CORBA.UNKNOWN(org.apache.yoko.orb.OB.MinorCodes
+                        .describeUnknown(org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException),
+                        org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
+                        org.omg.CORBA.CompletionStatus.COMPLETED_YES));
+            checkForException();
+        }
     }
 
-    public String unmarshalExceptionId() {
-        Assert._OB_assert(state_ == DowncallStateUserException);
-        int pos = in_._OB_pos();
-        String id = in_.read_string();
-        in_._OB_pos(pos);
-        return id;
+    public final String unmarshalExceptionId() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            Assert._OB_assert(state == State.USER_EXCEPTION);
+            int pos = in_._OB_pos();
+            String id = in_.read_string();
+            in_._OB_pos(pos);
+            return id;
+        }
     }
 
-    public boolean unsent() {
-        return state_ == DowncallStateUnsent;
+    public final boolean unsent() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.UNSENT;
+        }
     }
 
-    public boolean pending() {
-        return state_ == DowncallStatePending;
+    public final boolean pending() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.PENDING;
+        }
     }
 
-    public boolean noException() {
-        return state_ == DowncallStateNoException;
+    public final boolean noException() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.NO_EXCEPTION;
+        }
     }
 
-    public boolean userException() {
-        return state_ == DowncallStateUserException;
+    public final boolean userException() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.USER_EXCEPTION;
+        }
     }
 
-    public boolean failureException() {
-        return state_ == DowncallStateFailureException;
+    public final boolean failureException() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.FAILURE_EXCEPTION;
+        }
     }
 
-    public boolean systemException() {
-        return state_ == DowncallStateSystemException;
+    public final boolean systemException() {
+        try (AutoLock lock = stateLock.getReadLock()) {
+            return state == State.SYSTEM_EXCEPTION;
+        }
     }
 
-    private void setPendingImpl() {
-        Assert._OB_assert(responseExpected_);
-        state_ = DowncallStatePending;
-    }
-
-    public void setPending() {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setPendingImpl();
-                stateMonitor_.notify();
-            }
-        } else
-            setPendingImpl();
-    }
-
-    private void setNoExceptionImpl(org.apache.yoko.orb.CORBA.InputStream in) {
-        state_ = DowncallStateNoException;
-        if (in == null) {
-            Assert._OB_assert(!responseExpected_);
-        } else {
+    public final void setPending() {
+        try (AutoLock lock = stateLock.getWriteLock()) {
             Assert._OB_assert(responseExpected_);
+            state = State.PENDING;
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
+    }
+
+    public final void setNoException(org.apache.yoko.orb.CORBA.InputStream in) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            state = State.NO_EXCEPTION;
+            if (in == null) {
+                Assert._OB_assert(!responseExpected_);
+            } else {
+                Assert._OB_assert(responseExpected_);
+                in_ = in;
+                in_._OB_ORBInstance(orbInstance_);
+                CodeConverters codeConverters = client_.codeConverters();
+                in_._OB_codeConverters(codeConverters, GiopVersion.get(profileInfo_.major, profileInfo_.minor));
+            }
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
+    }
+
+    public final void setUserException(org.apache.yoko.orb.CORBA.InputStream in) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(in != null);
+            Assert._OB_assert(responseExpected_);
+            state = State.USER_EXCEPTION;
             in_ = in;
             in_._OB_ORBInstance(orbInstance_);
             CodeConverters codeConverters = client_.codeConverters();
             in_._OB_codeConverters(codeConverters, GiopVersion.get(profileInfo_.major, profileInfo_.minor));
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
         }
     }
 
-    public void setNoException(org.apache.yoko.orb.CORBA.InputStream in) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setNoExceptionImpl(in);
-                stateMonitor_.notify();
-            }
-        } else
-            setNoExceptionImpl(in);
-    }
-
-    private void setUserExceptionImpl(org.apache.yoko.orb.CORBA.InputStream in) {
-        Assert._OB_assert(in != null);
-        Assert._OB_assert(responseExpected_);
-        state_ = DowncallStateUserException;
-        in_ = in;
-        in_._OB_ORBInstance(orbInstance_);
-        CodeConverters codeConverters = client_.codeConverters();
-        in_._OB_codeConverters(codeConverters, GiopVersion.get(profileInfo_.major, profileInfo_.minor));
-    }
-
-    public void setUserException(org.apache.yoko.orb.CORBA.InputStream in) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setUserExceptionImpl(in);
-                stateMonitor_.notify();
-            }
-        } else
-            setUserExceptionImpl(in);
-    }
-
-    private void setUserExceptionImpl(org.omg.CORBA.UserException ex,
-            String exId) {
-        Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateUserException;
-        ex_ = ex;
-    }
-
     public void setUserException(org.omg.CORBA.UserException ex, String exId) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setUserExceptionImpl(ex, exId);
-                stateMonitor_.notify();
-            }
-        } else
-            setUserExceptionImpl(ex, exId);
-    }
-
-    private void setUserExceptionImpl(org.omg.CORBA.UserException ex) {
-        Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateUserException;
-        ex_ = ex;
-    }
-
-    public void setUserException(org.omg.CORBA.UserException ex) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setUserExceptionImpl(ex);
-                stateMonitor_.notify();
-            }
-        } else
-            setUserExceptionImpl(ex);
-    }
-
-    //
-    // Java only
-    //
-    // Required for portable stubs, which do not make the UserException
-    // instance available to the ORB
-    //
-    private void setUserExceptionImpl(String exId) {
-        Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateUserException;
-        exId_ = exId;
-        logger_.debug("Received user exception " + exId);
-    }
-
-    public void setUserException(String exId) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setUserExceptionImpl(exId);
-                stateMonitor_.notify();
-            }
-        } else
-            setUserExceptionImpl(exId);
-    }
-
-    private void setSystemExceptionImpl(org.omg.CORBA.SystemException ex) {
-        Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateSystemException;
-        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;
-                    CodeConverters codeConverters = new CodeConverters();
-                    codeConverters.outputWcharConverter = CodeSetDatabase.instance().getConverter(UTF16, UTF16);
-                    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, codeConverters, GIOP1_2)) {
-                        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) {
-                        throw (MARSHAL)(new MARSHAL(e.getMessage())).initCause(e);
-                    }
-                }
-            }
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(responseExpected_);
+            Assert._OB_assert(ex_ == null);
+            state = State.USER_EXCEPTION;
+            ex_ = ex;
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
         }
-        return ex;
     }
 
-    public void setSystemException(org.omg.CORBA.SystemException ex) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setSystemExceptionImpl(ex);
-                stateMonitor_.notify();
-            }
-        } else
-            setSystemExceptionImpl(ex);
+    public final void setUserException(org.omg.CORBA.UserException ex) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(responseExpected_);
+            Assert._OB_assert(ex_ == null);
+            state = State.USER_EXCEPTION;
+            ex_ = ex;
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
     }
 
-    private void setFailureExceptionImpl(org.omg.CORBA.SystemException ex) {
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateFailureException;
-        ex_ = ex;
-        logger_.debug("Received failure exception", ex);
+    public final void setUserException(String exId) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(responseExpected_);
+            Assert._OB_assert(ex_ == null);
+            state = State.USER_EXCEPTION;
+            exId_ = exId;
+            logger_.debug("Received user exception " + exId);
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
     }
 
-    public void setFailureException(org.omg.CORBA.SystemException ex) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setFailureExceptionImpl(ex);
-                stateMonitor_.notify();
-            }
-        } else
-            setFailureExceptionImpl(ex);
+    public final void setSystemException(org.omg.CORBA.SystemException ex) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(responseExpected_);
+            Assert._OB_assert(ex_ == null);
+            state = State.SYSTEM_EXCEPTION;
+            ex_ = ex;
+            logger_.debug("Received system exception", ex);
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
     }
 
-    private void setLocationForwardImpl(org.omg.IOP.IOR ior, boolean perm) {
+    public final void setFailureException(org.omg.CORBA.SystemException ex) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(ex_ == null);
+            state = State.FAILURE_EXCEPTION;
+            ex_ = ex;
+            logger_.debug("Received failure exception", ex);
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
+    }
+
+    public final void setLocationForward(org.omg.IOP.IOR ior, boolean perm) {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(responseExpected_);
+            Assert._OB_assert(forwardIOR_ == null);
+            state = perm ? State.FORWARD_PERM : State.FORWARD;
+            forwardIOR_ = ior;
+            if (null != stateWaitCondition) stateWaitCondition.signalAll();
+        }
         Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(forwardIOR_ == null);
-        if (perm)
-            state_ = DowncallStateForwardPerm;
-        else
-            state_ = DowncallStateForward;
-        forwardIOR_ = ior;
-    }
-
-    public void setLocationForward(org.omg.IOP.IOR ior, boolean perm) {
-        if (stateMonitor_ != null) {
-            synchronized (stateMonitor_) {
-                setLocationForwardImpl(ior, perm);
-                stateMonitor_.notify();
-            }
-        } else
-            setLocationForwardImpl(ior, perm);
     }
 
     //
-    // Initialize the state monitor. This operation must be called in
+    // Initialize the wait condition. This operation must be called in
     // order to be able to use one of the waitUntil...() operations
     // below
     //
-    public void initStateMonitor() {
-        Assert._OB_assert(stateMonitor_ == null);
-        stateMonitor_ = new java.lang.Object();
+    public final void allowWaiting() {
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(stateWaitCondition == null);
+            stateWaitCondition = lock.newCondition();
+        }
     }
 
-    //
-    // This operation try waits for a specific state, using the
-    // timeout from this downcall's policies. If the timeout expires,
-    // a NO_RESPONSE exception is raised.
-    //
-    // - If the first parameter is set to false, the operation returns
-    // immediately with false if the desired state cannot be
-    // reached.
-    //
-    // - If the return value is true, it's safe to access or modify
-    // the downcall object. If the return value if false, accessing
-    // or modifying the downcall object is not allowed, for thread
-    // safety reasons. (Because the downcall object is not thread
-    // safe.)
-    //
-    public boolean waitUntilCompleted(boolean block) {
+    /**
+     * This operation try waits for a completed state, using the
+     * timeout from this downcall's policies.
+     *
+     * @param block whether to wait for the call to complete
+     * @return true if the call has completed
+     * @throws NO_RESPONSE if a timeout was set and has elapsed
+     */
+    public final boolean waitUntilCompleted(boolean block) {
         //
         // Get the timeout
         //
         int t = policies_.requestTimeout;
 
         //
-        // Yield if non-blocking or blocking with zero timeout
-        //
-        if (!block || (block && t == 0)) {
-            Thread.yield();
-        }
-
-        //
         // Wait for the desired state, taking the timeout and blocking
         // flag into account
         //
-        Assert._OB_assert(stateMonitor_ != null);
-        synchronized (stateMonitor_) {
-            while (state_ == DowncallStateUnsent
-                    || state_ == DowncallStatePending) {
-                if (!block) {
-                    return false;
-                }
+        try (AutoLock lock = stateLock.getWriteLock()) {
+            Assert._OB_assert(stateWaitCondition != null);
+            while (state == State.UNSENT || state == State.PENDING) {
+                if (!block) return false;
 
                 try {
-                    if (t < 0) {
-                        stateMonitor_.wait();
+                    if (t <= 0) {
+                        stateWaitCondition.await();
                     } else {
-                        int oldState = state_;
+                        State oldState = state;
 
-                        stateMonitor_.wait(t);
+                        stateWaitCondition.await(t, TimeUnit.MILLISECONDS);
 
-                        if (state_ == oldState) {
-                            throw new org.omg.CORBA.NO_RESPONSE(
-                                    "Timeout during receive",
-                                    0,
-                                    org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
+                        if (state == oldState) {
+                            throw new NO_RESPONSE("Timeout during receive", 0, CompletionStatus.COMPLETED_MAYBE);
                         }
                     }
                 } 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 2cd687b..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
@@ -17,10 +17,21 @@
 
 package org.apache.yoko.orb.OB;
 
+import static org.apache.yoko.orb.OCI.GiopVersion.GIOP1_2;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 import org.apache.yoko.orb.CORBA.InputStream;
 import org.apache.yoko.orb.OB.Logger;
+import org.apache.yoko.orb.OCI.Buffer;
 import org.apache.yoko.orb.OCI.GiopVersion;
+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;
 import org.omg.SendingContext.CodeBase;
 
 abstract public class GIOPConnection implements DowncallEmitter, UpcallReturn {
@@ -557,8 +568,8 @@
 
         case org.omg.GIOP.ReplyStatusType_1_2._SYSTEM_EXCEPTION: {
             try {
-                org.omg.CORBA.SystemException ex = Util
-                        .unmarshalSystemException(in);
+                org.omg.CORBA.SystemException ex = Util.unmarshalSystemException(in);
+                ex = convertToUnknownExceptionIfAppropriate(ex, in, scl.value);
                 down.setSystemException(ex);
             } catch (org.omg.CORBA.SystemException ex) {
                 processException(State.Error, ex, false);
@@ -614,6 +625,18 @@
         }
     }
 
+    private SystemException convertToUnknownExceptionIfAppropriate(org.omg.CORBA.SystemException ex, InputStream is,
+            ServiceContext[] scl) {
+        if (ex instanceof UNKNOWN) {
+            for (ServiceContext sc : scl) {
+                if (sc.context_id == UnknownExceptionInfo.value) {
+                    return new UnresolvedException((UNKNOWN) ex, sc.context_data, is);
+                }
+            }
+        }
+        return ex;
+    }
+
     private void assignSendingContextRuntime(InputStream in, ServiceContext[] scl) {
         if (serverRuntime_ == null) {
             serverRuntime_
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 269edf5..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);
@@ -539,7 +539,7 @@
             // make the downcall thread-safe
             //
             if (down.responseExpected()) {
-                down.initStateMonitor();
+                down.allowWaiting();
             }
 
             // 
@@ -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/PIDowncall.java b/yoko-core/src/main/java/org/apache/yoko/orb/OB/PIDowncall.java
index ac094c5..6aa738b 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OB/PIDowncall.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OB/PIDowncall.java
@@ -17,6 +17,8 @@
 
 package org.apache.yoko.orb.OB;
 
+import org.apache.yoko.orb.util.AutoLock;
+
 public class PIDowncall extends Downcall {
     //
     // The IOR and the original IOR
@@ -48,74 +50,76 @@
     // ----------------------------------------------------------------------
 
     void checkForException() throws LocationForward, FailureException {
-        //
-        // If ex_ is set, but exId_ is not, then set it now
-        //
-        // TODO: Postpone this in Java?
-        //
-        if (ex_ != null && exId_ == null)
-            exId_ = Util.getExceptionId(ex_);
+        try (AutoLock lock = stateLock.getReadLock()) {
+            //
+            // If ex_ is set, but exId_ is not, then set it now
+            //
+            // TODO: Postpone this in Java?
+            //
+            if (ex_ != null && exId_ == null)
+                exId_ = Util.getExceptionId(ex_);
 
-        switch (state_) {
-        case DowncallStateUserException:
-            //
-            // For Java portable stubs, we'll have the repository ID
-            // but not the exception instance, so we pass UNKNOWN to
-            // the interceptors but DO NOT modify the Downcall state.
-            //
-            if (ex_ == null && exId_ != null) {
-                org.omg.CORBA.Any any = new org.apache.yoko.orb.CORBA.Any(
-                        orbInstance_);
-                org.omg.CORBA.UNKNOWN sys = new org.omg.CORBA.UNKNOWN(
-                        MinorCodes
+            switch (state) {
+                case USER_EXCEPTION:
+                    //
+                    // For Java portable stubs, we'll have the repository ID
+                    // but not the exception instance, so we pass UNKNOWN to
+                    // the interceptors but DO NOT modify the Downcall state.
+                    //
+                    if (ex_ == null && exId_ != null) {
+                        org.omg.CORBA.Any any = new org.apache.yoko.orb.CORBA.Any(
+                                orbInstance_);
+                        org.omg.CORBA.UNKNOWN sys = new org.omg.CORBA.UNKNOWN(
+                                MinorCodes
                                 .describeUnknown(org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException)
                                 + ": " + exId_,
-                        org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
-                        org.omg.CORBA.CompletionStatus.COMPLETED_YES);
-                org.omg.CORBA.UNKNOWNHelper.insert(any, sys);
-                org.omg.CORBA.UnknownUserException unk = new org.omg.CORBA.UnknownUserException(
-                        any);
-                piManager_.clientReceiveException(requestInfo_, false, unk,
-                        exId_);
+                                org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
+                                org.omg.CORBA.CompletionStatus.COMPLETED_YES);
+                        org.omg.CORBA.UNKNOWNHelper.insert(any, sys);
+                        org.omg.CORBA.UnknownUserException unk = new org.omg.CORBA.UnknownUserException(
+                                any);
+                        piManager_.clientReceiveException(requestInfo_, false, unk,
+                                exId_);
+                    }
+                    //
+                    // Only invoke interceptor if a user exception has been
+                    // set
+                    //
+                    if (ex_ != null)
+                        piManager_.clientReceiveException(requestInfo_, false, ex_,
+                                exId_);
+                    break;
+
+                case SYSTEM_EXCEPTION:
+                    Assert._OB_assert(ex_ != null);
+                    piManager_.clientReceiveException(requestInfo_, true, ex_, exId_);
+                    break;
+
+                case FAILURE_EXCEPTION:
+                    try {
+                        Assert._OB_assert(ex_ != null);
+                        piManager_.clientReceiveException(requestInfo_, true, ex_,
+                                exId_);
+                    } catch (org.omg.CORBA.SystemException ex) {
+                        //
+                        // Ignore any exception translations for failure
+                        // exceptions
+                        //
+                    }
+                    break;
+
+                case FORWARD:
+                case FORWARD_PERM:
+                    Assert._OB_assert(forwardIOR_ != null);
+                    piManager_.clientReceiveLocationForward(requestInfo_, forwardIOR_);
+                    break;
+
+                default:
+                    break;
             }
-            //
-            // Only invoke interceptor if a user exception has been
-            // set
-            //
-            if (ex_ != null)
-                piManager_.clientReceiveException(requestInfo_, false, ex_,
-                        exId_);
-            break;
 
-        case DowncallStateSystemException:
-            Assert._OB_assert(ex_ != null);
-            piManager_.clientReceiveException(requestInfo_, true, ex_, exId_);
-            break;
-
-        case DowncallStateFailureException:
-            try {
-                Assert._OB_assert(ex_ != null);
-                piManager_.clientReceiveException(requestInfo_, true, ex_,
-                        exId_);
-            } catch (org.omg.CORBA.SystemException ex) {
-                //
-                // Ignore any exception translations for failure
-                // exceptions
-                //
-            }
-            break;
-
-        case DowncallStateForward:
-        case DowncallStateForwardPerm:
-            Assert._OB_assert(forwardIOR_ != null);
-            piManager_.clientReceiveLocationForward(requestInfo_, forwardIOR_);
-            break;
-
-        default:
-            break;
+            super.checkForException();
         }
-
-        super.checkForException();
     }
 
     // ----------------------------------------------------------------------
@@ -143,52 +147,45 @@
     }
 
     public void postUnmarshal() throws LocationForward, FailureException {
-        //
-        // If the result of this downcall is a user exception, but no user
-        // exception could be unmarshalled, then use the system exception
-        // UNKNOWN, but keep the original exception ID
-        //
-        // In Java, the portable stubs only provide the repository ID of
-        // the user exception, not the exception instance. We want to
-        // report UNKNOWN to the interceptors, but do not want to change
-        // the downcall status if we have the repository ID.
-        //
-        if (state_ == DowncallStateUserException && ex_ == null
-                && exId_ == null) {
-            String id = unmarshalExceptionId();
-            setSystemException(new org.omg.CORBA.UNKNOWN(org.apache.yoko.orb.OB.MinorCodes
-                    .describeUnknown(org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException)
-                    + ": " + id, org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
-                    org.omg.CORBA.CompletionStatus.COMPLETED_YES));
-            exId_ = id;
+        try (AutoLock lock = stateLock.getReadLock()) {
+            //
+            // If the result of this downcall is a user exception, but no user
+            // exception could be unmarshalled, then use the system exception
+            // UNKNOWN, but keep the original exception ID
+            //
+            // In Java, the portable stubs only provide the repository ID of
+            // the user exception, not the exception instance. We want to
+            // report UNKNOWN to the interceptors, but do not want to change
+            // the downcall status if we have the repository ID.
+            //
+            if (state == State.USER_EXCEPTION && ex_ == null && exId_ == null) {
+                String id = unmarshalExceptionId();
+                setSystemException(new org.omg.CORBA.UNKNOWN(org.apache.yoko.orb.OB.MinorCodes
+                        .describeUnknown(org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException)
+                        + ": " + id, org.apache.yoko.orb.OB.MinorCodes.MinorUnknownUserException,
+                        org.omg.CORBA.CompletionStatus.COMPLETED_YES));
+                exId_ = id;
+            }
+    
+            super.postUnmarshal();
+    
+            //
+            // Java only - Downcall.checkForException() does not raise
+            // UserExceptions, so we return now and let the stub handle it
+            //
+            if (state == State.USER_EXCEPTION)
+                return;
+    
+            if (responseExpected_)
+                Assert._OB_assert(state == State.NO_EXCEPTION);
+            else
+                Assert._OB_assert(state == State.UNSENT || state == State.NO_EXCEPTION);
+            piManager_.clientReceiveReply(requestInfo_);
         }
-
-        super.postUnmarshal();
-
-        //
-        // Java only - Downcall.checkForException() does not raise
-        // UserExceptions, so we return now and let the stub handle it
-        //
-        if (state_ == DowncallStateUserException)
-            return;
-
-        if (responseExpected_)
-            Assert._OB_assert(state_ == DowncallStateNoException);
-        else
-            Assert._OB_assert(state_ == DowncallStateUnsent
-                    || state_ == DowncallStateNoException);
-        piManager_.clientReceiveReply(requestInfo_);
     }
 
     public void setUserException(org.omg.CORBA.UserException ex, String exId) {
         super.setUserException(ex, exId);
         exId_ = exId;
     }
-
-    public void setUserException(org.omg.CORBA.UserException ex) {
-        Assert._OB_assert(responseExpected_);
-        Assert._OB_assert(ex_ == null);
-        state_ = DowncallStateUserException;
-        ex_ = ex;
-    }
 }
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/OBCORBA/AutoReadWriteLock.java b/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/AutoReadWriteLock.java
deleted file mode 100644
index 85ae80f..0000000
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/AutoReadWriteLock.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.apache.yoko.orb.OBCORBA;
-
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-class AutoLock implements AutoCloseable{
-    final AtomicReference<Lock> lockRef;
-    
-    AutoLock(Lock lock) {
-        lockRef = new AtomicReference<>(lock);
-        lock.lock();
-    }
-    
-    @Override
-    public void close() {
-        Lock lock = lockRef.getAndSet(null);
-        if (lock != null) lock.unlock();
-    }
-}
-
-class AutoReadWriteLock {
-    private final ReadWriteLock lock = new ReentrantReadWriteLock();
-    
-    public AutoLock getReadLock() {
-        return new AutoLock(lock.readLock());
-    }
-
-    public AutoLock getWriteLock() {
-        return new AutoLock(lock.writeLock());
-    }
-}
\ No newline at end of file
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/ORB_impl.java b/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/ORB_impl.java
index c16544b..766f9aa 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/ORB_impl.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OBCORBA/ORB_impl.java
@@ -25,6 +25,8 @@
 import org.apache.yoko.orb.cmsf.CmsfClientInterceptor;
 import org.apache.yoko.orb.cmsf.CmsfIORInterceptor;
 import org.apache.yoko.orb.cmsf.CmsfServerInterceptor;
+import org.apache.yoko.orb.util.AutoLock;
+import org.apache.yoko.orb.util.AutoReadWriteLock;
 import org.apache.yoko.orb.util.GetSystemPropertyAction;
 import org.apache.yoko.util.osgi.ProviderLocator;
 import org.omg.CORBA.OBJECT_NOT_EXIST;
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
new file mode 100644
index 0000000..c2dbf5d
--- /dev/null
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoLock.java
@@ -0,0 +1,51 @@
+package org.apache.yoko.orb.util;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+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)
+            return;
+        for (int i = 0; i < downgradeHeld; i++) {
+            downgradeLock.lock();
+        }
+        lock.unlock();
+    }
+
+    public Condition newCondition() {
+        return lockRef.get().newCondition();
+    }
+
+    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
new file mode 100644
index 0000000..f9b47d0
--- /dev/null
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/util/AutoReadWriteLock.java
@@ -0,0 +1,15 @@
+package org.apache.yoko.orb.util;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class AutoReadWriteLock {
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    
+    public AutoLock getReadLock() {
+        return new AutoLock(lock.readLock());
+    }
+
+    public AutoLock getWriteLock() {
+        return new AutoLock(lock.writeLock(), lock.readLock(), lock.getReadHoldCount());
+    }
+}
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FieldDescriptor.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FieldDescriptor.java
index a19d21b..87f37da 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FieldDescriptor.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/FieldDescriptor.java
@@ -1,20 +1,20 @@
 /**
-*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-*  contributor license agreements.  See the NOTICE file distributed with
-*  this work for additional information regarding copyright ownership.
-*  The ASF licenses this file to You under the Apache License, Version 2.0
-*  (the "License"); you may not use this file except in compliance with
-*  the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-*  Unless required by applicable law or agreed to in writing, software
-*  distributed under the License is distributed on an "AS IS" BASIS,
-*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*  See the License for the specific language governing permissions and
-*  limitations under the License.
-*/ 
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */ 
 
 package org.apache.yoko.rmi.impl;
 
@@ -29,7 +29,7 @@
 import org.omg.CORBA.ValueMember;
 
 public abstract class FieldDescriptor extends ModelElement implements
-        Comparable {
+Comparable {
     static Logger logger = Logger.getLogger(FieldDescriptor.class.getName());
 
     org.apache.yoko.rmi.util.corba.Field field;
@@ -160,7 +160,7 @@
 
         } else {
             if(org.omg.CORBA.Object.class.isAssignableFrom(type)) {
-        	return new CorbaObjectFieldDescriptor(owner, type, name, f);
+                return new CorbaObjectFieldDescriptor(owner, type, name, f);
             }
             if (java.lang.Object.class.equals(type)
                     || java.io.Externalizable.class.equals(type)
@@ -168,7 +168,7 @@
                 return new AnyFieldDescriptor(owner, type, name, f);
 
             } else if (java.rmi.Remote.class.isAssignableFrom(type) 
-        	    || java.rmi.Remote.class.equals(type))
+                    || java.rmi.Remote.class.equals(type))
             {
                 return new RemoteFieldDescriptor(owner, type, name, f);
 
@@ -1143,7 +1143,7 @@
 class CorbaObjectFieldDescriptor extends FieldDescriptor {
 
     protected CorbaObjectFieldDescriptor(Class owner, Class type, String name, Field f) {
-	super(owner, type, name, f);
+        super(owner, type, name, f);
     }
 
     void copyState(final Object orig, final Object copy, CopyState state) {
@@ -1167,31 +1167,31 @@
     void read(ObjectReader reader, Object obj) throws IOException {
         Object value = reader.readCorbaObject(null);
         try {
-	    field.set(obj, value);
-	} catch (IllegalAccessException e) {
-	    throw (IOException)new IOException(e.getMessage()).initCause(e);
-	}
+            field.set(obj, value);
+        } catch (IllegalAccessException e) {
+            throw (IOException)new IOException(e.getMessage()).initCause(e);
+        }
     }
 
     void readFieldIntoMap(ObjectReader reader, Map map) throws IOException {
-	Object value = reader.readCorbaObject(null);
-	map.put(getJavaName(), value);
-	
+        Object value = reader.readCorbaObject(null);
+        map.put(getJavaName(), value);
+
     }
 
     void write(ObjectWriter writer, Object obj) throws IOException {
-	try {
-	    writer.writeCorbaObject(field.get(obj));
-	}
-	catch(IllegalAccessException e) {
-	    throw (IOException)new IOException(e.getMessage()).initCause(e);
-	}
+        try {
+            writer.writeCorbaObject(field.get(obj));
+        }
+        catch(IllegalAccessException e) {
+            throw (IOException)new IOException(e.getMessage()).initCause(e);
+        }
     }
 
     void writeFieldFromMap(ObjectWriter writer, Map map) throws IOException {
         org.omg.CORBA.Object value = (org.omg.CORBA.Object) map.get(getJavaName());
         writer.writeCorbaObject(value);
-	
+
     }
-    
+
 }