Merge branch 'nr.dev' into 'ibm-trunk'

Nr.dev

Further fixes for customer-reported problems

See merge request !68
diff --git a/yoko-core/src/main/java/org/apache/yoko/orb/OCI/IIOP/Connector_impl.java b/yoko-core/src/main/java/org/apache/yoko/orb/OCI/IIOP/Connector_impl.java
index e2a737e..b257a22 100644
--- a/yoko-core/src/main/java/org/apache/yoko/orb/OCI/IIOP/Connector_impl.java
+++ b/yoko-core/src/main/java/org/apache/yoko/orb/OCI/IIOP/Connector_impl.java
@@ -459,6 +459,7 @@
     // ------------------------------------------------------------------
 
     private Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ConnectionHelper helper, ExtendedConnectionHelper xhelper, Codec codec) {
+        if ((null == helper) && (null == xhelper)) throw new IllegalArgumentException("Both connection helpers must not be null");
         ior_ = ior;
         policies_ = policies;
         keepAlive_ = keepAlive;
@@ -474,8 +475,8 @@
         this(ior, policies, host, port, keepAlive, cb, lm, helper, null, codec);
     }
 
-    public Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ExtendedConnectionHelper helper, Codec codec) {
-        this(ior, policies, host, port, keepAlive, cb, lm, null, helper, codec);
+    public Connector_impl(IOR ior, Policy[] policies, String host, int port, boolean keepAlive, ConnectCB[] cb, ListenerMap lm, ExtendedConnectionHelper xhelper, Codec codec) {
+        this(ior, policies, host, port, keepAlive, cb, lm, null, xhelper, codec);
     }
 
     public void finalize() throws Throwable {
diff --git a/yoko-core/src/test/java/org/apache/yoko/AbstractOrbTestBase.java b/yoko-core/src/test/java/org/apache/yoko/AbstractOrbTestBase.java
index 2f702b4..ee97b45 100644
--- a/yoko-core/src/test/java/org/apache/yoko/AbstractOrbTestBase.java
+++ b/yoko-core/src/test/java/org/apache/yoko/AbstractOrbTestBase.java
@@ -97,9 +97,6 @@
         server.launch();
         Future<Void> serverFuture = server.invokeMainAsync(serverClass, serverArgs);
         waitForFile();
-        // TODO: Need to find a better way, this slows down testing unneccesarily,
-        // and is somewhat non-robust.
-        Thread.sleep(1000);
         client.invokeMain(clientClass, clientArgs);
         try {
             serverFuture.get(2, SECONDS);
diff --git a/yoko-core/src/test/java/test/poa/PMSTestThread.java b/yoko-core/src/test/java/test/poa/PMSTestThread.java
index 1002cf6..a882e7e 100644
--- a/yoko-core/src/test/java/test/poa/PMSTestThread.java
+++ b/yoko-core/src/test/java/test/poa/PMSTestThread.java
@@ -17,47 +17,48 @@
 
 package test.poa;
 
-import org.omg.CORBA.*;
-import org.omg.PortableServer.*;
-import org.omg.PortableServer.POAPackage.*;
-import java.io.*;
+import java.util.concurrent.CountDownLatch;
 
 final class PMSTestThread extends Thread {
-    private Test test_;
+    private final Test test_;
 
-    private int state_;
+    private final CountDownLatch startLatch = new CountDownLatch(1);
+    public volatile Result result = null;
 
-    final static int NONE = 0;
-
-    final static int CALL_STARTED = 1;
-
-    final static int CALL_FAILURE = 2;
-
-    final static int CALL_SUCCESS = 3;
-
-    private synchronized void setState(int val) {
-        state_ = val;
-    }
+    public enum Result { SUCCESS, FAILURE, ERROR };
 
     public void run() {
-        setState(CALL_STARTED);
+        startLatch.countDown();
         try {
             test_.aMethod();
+            result = Result.SUCCESS;
         } catch (org.omg.CORBA.TRANSIENT ex) {
-            setState(CALL_FAILURE);
+            result = Result.FAILURE;
             return;
         } catch (org.omg.CORBA.SystemException ex) {
+            result = Result.ERROR;
             System.err.println("Unexpected: " + ex);
         }
-        setState(CALL_SUCCESS);
     }
 
-    synchronized int callState() {
-        return state_;
+    public void waitForStart() {
+        do {
+            try {
+                startLatch.await();
+                return;
+            } catch (InterruptedException ie) {}
+        } while (true);
+    }
+
+    public void waitForEnd() {
+        while (isAlive()) {
+            try {
+                join();
+            } catch (InterruptedException ie) {}
+        }
     }
 
     PMSTestThread(Test test) {
         test_ = test;
-        state_ = NONE;
     }
 }
diff --git a/yoko-core/src/test/java/test/poa/TestDispatchStrategyServer.java b/yoko-core/src/test/java/test/poa/TestDispatchStrategyServer.java
index 258e9e3..ea03185 100644
--- a/yoko-core/src/test/java/test/poa/TestDispatchStrategyServer.java
+++ b/yoko-core/src/test/java/test/poa/TestDispatchStrategyServer.java
@@ -17,135 +17,78 @@
 
 package test.poa;
 
-import java.io.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashSet;
 import java.util.Properties;
+import java.util.Set;
 
 public final class TestDispatchStrategyServer extends test.common.TestBase {
     //
     // Implementation to test same thread dispatch strategy
     //
-    final static class TestSameThread_impl extends TestPOA {
-        private Thread thread_;
+    abstract static class AbstractTest extends TestPOA {
+        private volatile boolean failed = false;
 
-        private boolean failed_;
-
-        private boolean first_;
-
-        TestSameThread_impl() {
-            failed_ = false;
-            first_ = true;
+        public final boolean failed() {
+            return failed;
         }
 
-        public void aMethod() {
-            //
-            // Test to ensure that all requests handled by the same thread
-            //
-            if (first_) {
-                thread_ = Thread.currentThread();
-                first_ = false;
-            } else if (!Thread.currentThread().equals(thread_)) {
-                failed_ = true;
+        protected void fail() {
+            failed = true;
+        }
+    }
+
+    abstract static class AbstractTestPool extends AbstractTest {
+        private final Set<Thread> threadSet = new HashSet<>();
+        private final int maxSize;
+
+        AbstractTestPool(int maxSize) {
+            this.maxSize = maxSize;
+        }
+
+        public final synchronized void aMethod() {
+            final Thread thisThread = Thread.currentThread();
+            if (threadSet.contains(thisThread)) return;
+            if (threadSet.size() < maxSize) {
+                threadSet.add(thisThread);
+                return;
             }
-
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException ex) {
-            }
+            fail();
         }
+    }
 
-        public boolean failed() {
-            return failed_;
-        }
+    final static class TestSameThread_impl extends AbstractTestPool {
+        TestSameThread_impl() { super(1); }
     }
 
     //
     // Implementation to test thread per request dispatch strategy
     //
-    final static class TestThreadPerReq_impl extends TestPOA {
-        private Thread threads_[];
+    final static class TestThreadPerReq_impl extends AbstractTest {
+        private final Set<Thread> threadSet = new HashSet<>();
 
-        private int thread_count_;
-
-        private boolean failed_;
-
-        TestThreadPerReq_impl() {
-            failed_ = false;
-            thread_count_ = 0;
-            threads_ = new Thread[5];
-        }
-
-        public void aMethod() {
-            int idx;
-            synchronized (this) {
-                //
-                // Test to ensure that each request is being handled
-                // by a different thread.
-                //
-                for (idx = 0; idx < thread_count_; idx++) {
-                    if (Thread.currentThread().equals(threads_[idx]))
-                        failed_ = true;
-                }
-
-                if (idx == thread_count_) {
-                    threads_[thread_count_++] = Thread.currentThread();
-                }
+        public synchronized void aMethod() {
+            final Thread thisThread = Thread.currentThread();
+            //
+            // Test to ensure that each request is being handled
+            // by a different thread.
+            //
+            if (threadSet.contains(thisThread)) {
+                fail();
+                return;
             }
-
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException ex) {
-            }
-        }
-
-        public boolean failed() {
-            return failed_;
+            threadSet.add(thisThread);
         }
     }
 
     //
     // Implementation to test thread pool dispatch strategy
     //
-    final static class TestThreadPool_impl extends TestPOA {
-        private Thread threads_[];
-
-        private int thread_count_;
-
-        private boolean failed_;
-
-        TestThreadPool_impl() {
-            failed_ = false;
-            thread_count_ = 0;
-            threads_ = new Thread[2];
-        }
-
-        public void aMethod() {
-            synchronized (this) {
-                //
-                // Test to ensure that all requests are handled only by
-                // the two threads in the thread pool.
-                //
-                if (thread_count_ == 0) {
-                    threads_[0] = Thread.currentThread();
-                    ++thread_count_;
-                } else if (!Thread.currentThread().equals(threads_[0])) {
-                    if (thread_count_ == 1) {
-                        threads_[1] = Thread.currentThread();
-                        ++thread_count_;
-                    } else if (!Thread.currentThread().equals(threads_[1])) {
-                        failed_ = true;
-                    }
-                }
-            }
-
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException ex) {
-            }
-        }
-
-        public boolean failed() {
-            return failed_;
-        }
+    final static class TestThreadPool_impl extends AbstractTestPool {
+        TestThreadPool_impl() { super(2); }
     }
 
     //
diff --git a/yoko-core/src/test/java/test/poa/TestPOAManagerCommon.java b/yoko-core/src/test/java/test/poa/TestPOAManagerCommon.java
index 4241b27..9a5895a 100644
--- a/yoko-core/src/test/java/test/poa/TestPOAManagerCommon.java
+++ b/yoko-core/src/test/java/test/poa/TestPOAManagerCommon.java
@@ -23,45 +23,55 @@
 import org.omg.PortableServer.*;
 import org.omg.PortableServer.POAPackage.*;
 
+import java.util.concurrent.CountDownLatch;
+
 final class TestPOAManagerCommon extends test.common.TestBase {
     final static class TestHoldingState extends Thread {
         private Test test_;
 
-        private int state_;
+        private final CountDownLatch startLatch = new CountDownLatch(1);
+        public volatile Result result = null;
 
-        final static int NONE = 0;
-
-        final static int CALL_STARTED = 1;
-
-        final static int CALL_FAILURE = 2;
-
-        final static int CALL_SUCCESS = 3;
-
-        private synchronized void setState(int val) {
-            state_ = val;
-        }
+        public enum Result { SUCCESS, FAILURE, ERROR };
 
         TestHoldingState(Test test) {
             test_ = test;
-            state_ = NONE;
         }
 
         public void run() {
-            setState(CALL_STARTED);
+            startLatch.countDown();
             try {
                 test_.aMethod();
+                result = Result.SUCCESS;
             } catch (TRANSIENT ex) {
-                setState(CALL_FAILURE);
+                result = Result.FAILURE;
                 return;
             } catch (SystemException ex) {
+                result = Result.ERROR;
                 System.err.println("Unexpected: " + ex);
                 ex.printStackTrace();
             }
-            setState(CALL_SUCCESS);
         }
 
-        synchronized int callState() {
-            return state_;
+        public void waitForStart() {
+            do {
+                try {
+                    startLatch.await();
+                    return;
+                } catch (InterruptedException e) {
+                }
+            } while (true);
+        }
+
+
+
+        public void waitForEnd() {
+            while (isAlive()) {
+                try {
+                    join();
+                } catch (java.lang.InterruptedException e) {
+                }
+            }
         }
     }
 
@@ -142,33 +152,16 @@
 
             TestHoldingState t = new TestHoldingState(info[i].obj);
             t.start();
-
-            //
-            // Wait for the call to start
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-                // Ignore
-            }
-
-            assertTrue(t.callState() == TestHoldingState.CALL_STARTED);
+            t.waitForStart();
 
             try {
                 manager.activate();
             } catch (test.poa.POAManagerProxyPackage.AdapterInactive ex) {
                 assertTrue(false);
             }
+            t.waitForEnd();
+            assertTrue(t.result == TestHoldingState.Result.SUCCESS);
 
-            //
-            // Wait for the call to complete
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-            }
-
-            assertTrue(t.callState() == TestHoldingState.CALL_SUCCESS);
 
             //
             // Test discard_requests when holding.
@@ -182,18 +175,7 @@
 
             t = new TestHoldingState(info[i].obj);
             t.start();
-
-            //
-            // Wait for the call to start
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-                // Ignore
-            }
-
-            assertTrue(t.callState() == TestHoldingState.CALL_STARTED);
-
+            t.waitForStart();
             try {
                 manager.discard_requests(false);
                 assertTrue(manager.get_state() == test.poa.POAManagerProxyPackage.State.DISCARDING);
@@ -208,16 +190,11 @@
                 // Expected
             }
 
-            while (t.isAlive()) {
-                try {
-                    t.join();
-                } catch (java.lang.InterruptedException e) {
-                }
-            }
+            t.waitForEnd();
             //
             // Queued call should have been discarded.
             //
-            assertTrue(t.callState() == TestHoldingState.CALL_FAILURE);
+            assertTrue(t.result == TestHoldingState.Result.FAILURE);
 
             //
             // Test hold_requests when discarding.
@@ -231,17 +208,7 @@
 
             t = new TestHoldingState(info[i].obj);
             t.start();
-
-            //
-            // Wait for the call to start
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-                // Ignore
-            }
-
-            assertTrue(t.callState() == TestHoldingState.CALL_STARTED);
+            t.waitForStart();
 
             try {
                 manager.activate();
@@ -249,15 +216,8 @@
                 assertTrue(false);
             }
 
-            //
-            // Wait for the call to complete
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-            }
-
-            assertTrue(t.callState() == TestHoldingState.CALL_SUCCESS);
+            t.waitForEnd();
+            assertTrue(t.result == TestHoldingState.Result.SUCCESS);
 
             //
             // Try deactivate with wait completion == true,
diff --git a/yoko-core/src/test/java/test/poa/TestPOAManagerServer.java b/yoko-core/src/test/java/test/poa/TestPOAManagerServer.java
index 73027d7..b609416 100644
--- a/yoko-core/src/test/java/test/poa/TestPOAManagerServer.java
+++ b/yoko-core/src/test/java/test/poa/TestPOAManagerServer.java
@@ -117,10 +117,8 @@
             POA retain = null;
             try {
                 retain = root.create_POA("retain", null, policies);
-            } catch (AdapterAlreadyExists ex) {
-                throw new RuntimeException();
-            } catch (InvalidPolicy ex) {
-                throw new RuntimeException();
+            } catch (AdapterAlreadyExists | InvalidPolicy ex) {
+                throw new RuntimeException(ex);
             }
 
             POAManager retainManager = retain.the_POAManager();
@@ -133,12 +131,8 @@
             byte[] oid = ("test").getBytes();
             try {
                 retain.activate_object_with_id(oid, testImpl);
-            } catch (ObjectAlreadyActive ex) {
-                assertTrue(false);
-            } catch (ServantAlreadyActive ex) {
-                assertTrue(false);
-            } catch (WrongPolicy ex) {
-                assertTrue(false);
+            } catch (ObjectAlreadyActive | ServantAlreadyActive | WrongPolicy ex) {
+                throw new RuntimeException(ex);
             }
 
             Test test = testImpl._this();
@@ -147,12 +141,8 @@
             byte[] oidDSI = ("testDSI").getBytes();
             try {
                 retain.activate_object_with_id(oidDSI, testDSIImpl);
-            } catch (ObjectAlreadyActive ex) {
-                assertTrue(false);
-            } catch (ServantAlreadyActive ex) {
-                assertTrue(false);
-            } catch (WrongPolicy ex) {
-                assertTrue(false);
+            } catch (ObjectAlreadyActive | ServantAlreadyActive | WrongPolicy ex) {
+                throw new RuntimeException(ex);
             }
 
             org.omg.CORBA.Object objDSI = retain.create_reference_with_id(
@@ -179,13 +169,7 @@
             //
             PMSTestThread t = new PMSTestThread(test);
             t.start();
-
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-            }
-
-            assertTrue(t.callState() == PMSTestThread.CALL_STARTED);
+            t.waitForStart();
 
             //
             // Run implementation. This should cause the blocked call in
@@ -195,19 +179,11 @@
                 manager.activate();
                 retainManager.activate();
             } catch (org.omg.PortableServer.POAManagerPackage.AdapterInactive ex) {
-                throw new RuntimeException();
+                throw new RuntimeException(ex);
             }
+            t.waitForEnd();
 
-            //
-            // Wait for the call to complete
-            //
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException ex) {
-                // Ignore
-            }
-
-            assertTrue(t.callState() == PMSTestThread.CALL_SUCCESS);
+            assertTrue(t.result == PMSTestThread.Result.SUCCESS);
 
             new TestPOAManagerCommon(proxy, info);
 
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ArrayDescriptor.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ArrayDescriptor.java
index 2cedbfa..ca4e0b1 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ArrayDescriptor.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ArrayDescriptor.java
@@ -185,27 +185,20 @@
         _out.write_value((Serializable)value, getRepositoryID());
     }
 
-    ValueMember[] getValueMembers() {
+    @Override
+    protected final ValueMember[] genValueMembers() {
+        final ValueMember[] members = new ValueMember[1];
+        final TypeDescriptor elemDesc = repo.getDescriptor(elementType);
+        final String elemRepID = elemDesc.getRepositoryID();
 
-        if (_value_members == null) {
+        final ORB orb = ORB.init();
+        TypeCode memberTC = orb.create_sequence_tc(0, elemDesc.getTypeCode());
 
-            _value_members = new ValueMember[1];
-
-            TypeDescriptor elemDesc = repo.getDescriptor(elementType);
-
-            String elemRepID = elemDesc.getRepositoryID();
-
-            ORB orb = ORB.init();
-            TypeCode memberTC = orb.create_sequence_tc(0, elemDesc
-                    .getTypeCode());
-
-            _value_members[0] = new ValueMember("", // member has no name!
+        members[0] = new ValueMember("", // member has no name!
                     elemRepID, this.getRepositoryID(), "1.0", memberTC, null,
                     (short) 1);
-            // public
-        }
 
-        return _value_members;
+        return members;
     }
 
     @Override
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
index ed66893..aea1298 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/TypeDescriptor.java
@@ -208,14 +208,17 @@
 
     @Override
     protected void init() {
-        typeCode = genTypeCode();
+        getTypeCode();
     }
 
     private volatile TypeCode typeCode = null;
     protected abstract TypeCode genTypeCode();
     final TypeCode getTypeCode() {
-        // typeCode should have already been set from within init(), so this is just defensive
-        if (null == typeCode) typeCode = genTypeCode();
+        if (null == typeCode) {
+            synchronized (repo) {
+                if (null == typeCode) typeCode = genTypeCode();
+            }
+        }
         return typeCode;
     }
     protected final void setTypeCode(TypeCode tc) {
diff --git a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java
index e6b1849..6e66d1c 100755
--- a/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java
+++ b/yoko-rmi-impl/src/main/java/org/apache/yoko/rmi/impl/ValueDescriptor.java
@@ -821,19 +821,23 @@
         return _hash_code;
     }
 
-    protected ValueMember[] _value_members = null;
-
-    private ValueMember[] getValueMembers() {
-        getTypeCode(); // ensure recursion through typecode for non-array types
-
-        if (_value_members == null) {
-            _value_members = new ValueMember[_fields.length];
-            for (int i = 0; i < _fields.length; i++) {
-                _value_members[i] = _fields[i].getValueMember(repo);
-            }
+    private volatile ValueMember[] valueMembers = null;
+    protected ValueMember[] genValueMembers() {
+        final ValueMember[] members = new ValueMember[_fields.length];
+        for (int i = 0; i < _fields.length; i++) {
+            members[i] = _fields[i].getValueMember(repo);
         }
 
-        return _value_members;
+        return members;
+    }
+    final ValueMember[] getValueMembers() {
+        getTypeCode(); // ensure recursion through typecode
+        if (null == valueMembers) {
+            synchronized (repo) {
+                if (null == valueMembers) valueMembers = genValueMembers();
+            }
+        }
+        return valueMembers;
     }
 
     @Override