package alma.acs.container.corba;
import java.util.logging.Level;
import alma.acs.component.ComponentQueryDescriptor;
import alma.acs.component.client.ComponentClientTestCase;
import alma.jconttest.DummyComponent;
import alma.jconttest.DummyComponentHelper;
/**
* Tests {@link alma.acs.container.corba.AcsCorba} and related usage of ORB and POAs.
* Requires ACS runtime with a remote container.
*
* @author hsommer
* @see alma.acs.container.corba.AcsCorbaTest
*/
public class AcsCorbaTestWithContainer extends ComponentClientTestCase {
private static final String DUMMYCOMP_TYPENAME = "IDL:alma/jconttest/DummyComponent:1.0";
private DummyComponent dummyComponent;
// simple otherthread-to-mainthread exception passing
private volatile Throwable exceptionInThread;
public AcsCorbaTestWithContainer() throws Exception {
super("AcsCorbaTestWithContainer");
}
protected void setUp() throws Exception {
Thread.sleep(2000); // to make sure that logging client is up and captures all logs
super.setUp();
}
protected void tearDown() throws Exception {
m_logger.info("done, tearDown");
super.tearDown();
}
public void testParallelCalls() throws Exception {
org.omg.CORBA.Object compObj = getContainerServices().getDynamicComponent(new ComponentQueryDescriptor(null, DUMMYCOMP_TYPENAME), false);
assertNotNull(compObj);
dummyComponent = DummyComponentHelper.narrow(compObj);
String compName = dummyComponent.name();
assertNotNull(compName);
exceptionInThread = null;
// run a call to 'callThatTakesSomeTime' from a client thread
Runnable compMethodCallRunnable = new Runnable() {
public void run() {
try {
dummyComponent.callThatTakesSomeTime(2000);
} catch (Exception ex) {
m_logger.log(Level.SEVERE, "Async client call 'dummyComponent#callThatTakesSomeTime' failed with exception.", ex);
exceptionInThread = ex;
}
}
};
(new Thread(compMethodCallRunnable)).start();
// now run another call from the main thread
Thread.sleep(500); // just to make sure the first call is out
compMethodCallRunnable.run();
// some other parallel call that uses ContainerServices
getContainerServices().getDynamicComponent(new ComponentQueryDescriptor(null, DUMMYCOMP_TYPENAME), false);
assertNull("got an exception in the first of two calls", exceptionInThread);
}
/**
* Activates / deactivates a component 10 times, each time calling a method that still runs while
* its POA is getting deactivated. The purpose is to check the container's ability to wait for currently
* processing requests to terminate, before <code>cleanUp</code> is called on the component.
* <p>
* TODO: extend this scenario so that another collocated component issues the long lasting call.
* This may not work due to a JacORB bug, which we should find out about.
*/
public void testComponentPOALifecycleAsync() throws Exception {
_testComponentPOALifecycle(true, 10);
}
/**
* @param destroyWhileBusy
* @param iterations
* @throws Exception
*/
private void _testComponentPOALifecycle(boolean destroyWhileBusy, int iterations) throws Exception {
// times in milliseconds
final int remoteCallDurationMin = (destroyWhileBusy ? 2000 : 0);
final int callOverheadMax = 600;
for (int i=0; i < iterations; i++) {
m_logger.info("Will create, use and destroy component instance #" + i);
org.omg.CORBA.Object compObj = getContainerServices().getDynamicComponent(
new ComponentQueryDescriptor(null, DUMMYCOMP_TYPENAME), false);
assertNotNull(compObj);
dummyComponent = DummyComponentHelper.narrow(compObj);
String compName = dummyComponent.name();
assertNotNull(compName);
exceptionInThread = null;
// make CORBA calls to the component, and have it destroyed
dummyComponent.dummyComponentsCanDoCloseToNothing();
if (destroyWhileBusy) {
Runnable compMethodCallRunnable = new Runnable() {
public void run() {
try {
dummyComponent.callThatTakesSomeTime(remoteCallDurationMin);
} catch (Exception ex) {
m_logger.log(Level.SEVERE, "Async client call 'dummyComponent#callThatTakesSomeTime' failed with exception.", ex);
exceptionInThread = ex;
}
}
};
m_logger.info("Will release component while active request is still running.");
(new Thread(compMethodCallRunnable)).start();
// Sleep a bit so that we are sure the component method 'callThatTakesSomeTime' is executing (=sleeping).
// TODO: use proper synchronization to wait until dymmyComponent has received the call to 'callThatTakesSomeTime'
// this could be done using ACS callbacks.
Thread.sleep(callOverheadMax);
}
else {
dummyComponent.callThatTakesSomeTime(remoteCallDurationMin);
}
// we expect the releaseComponent call to take some time, because the container must wait for the
// currently active call to finish before the component can be unloaded.
// Without any call and container overhead, the component is busy already for as long as we slept (=callOverheadMax).
// In that case we should measure timeReleaseCompCall == remoteCallDurationMin-callOverheadMax.
// Any overhead in the 'callThatTakesSomeTime' and the return of 'releaseComponent' only increases the measured timeReleaseCompCall.
// When running the test, we still see occasional failures of returning a few milliseconds too early.
// 2012-06-13: Assuming that these errors come from granularity issues with the timer and that measuring nanoseconds
// will improve this situation, we change from System.currentTimeMillis diffs to using System.nanoTime().
long timeBeforeRelease = System.nanoTime();
getContainerServices().releaseComponent(compName);
int timeReleaseCompCallMillis = (int) ((System.nanoTime() - timeBeforeRelease) / 1000000);
int timeReleaseCompCallMillisExpectedMin = remoteCallDurationMin - callOverheadMax;
int timeReleaseCompCallMillisExpectedMax = timeReleaseCompCallMillisExpectedMin + 2 * callOverheadMax;
if (destroyWhileBusy) {
assertTrue("Releasing component '" + compName + "' took " + timeReleaseCompCallMillis + " ms, when between "
+ timeReleaseCompCallMillisExpectedMin + " ms and " + timeReleaseCompCallMillisExpectedMax + " were expected.",
timeReleaseCompCallMillis >= remoteCallDurationMin-callOverheadMax && timeReleaseCompCallMillis <= timeReleaseCompCallMillisExpectedMax);
}
if (exceptionInThread != null) {
fail("asynchronous component call number " + i + " (callThatTakesSomeTime) failed: " + exceptionInThread.toString());
}
}
}
}