Skip to content

Commit

Permalink
PORT-122: Added support for enable/disable callbacks. When enabled, a
Browse files Browse the repository at this point in the history
block is put on tick processing. Added an implementation of a support
service message (getKnownObjectClassHandle()) as its absence was
breaking the test. Not sure why it was left unimplemented as it was
about 4s work, but it's done now.
  • Loading branch information
timpokorny committed Mar 26, 2013
1 parent 5fe9de5 commit 76ce0e8
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4884,8 +4884,13 @@ public ObjectClassHandle getKnownObjectClassHandle( ObjectInstanceHandle theObje
NotConnected,
RTIinternalError
{
featureNotSupported( "getKnownObjectClassHandle()" );
return null;
helper.checkJoined();

OCInstance instance = helper.getState().getRepository().getInstance( theObject.hashCode() );
if( instance == null )
throw new ObjectInstanceNotKnown( "handle: " + theObject );
else
return new HLA1516eHandle( instance.getDiscoveredClassHandle() );
}

// 10.9
Expand Down Expand Up @@ -5401,13 +5406,19 @@ public boolean evokeMultipleCallbacks( double approximateMinimumTimeInSeconds,
// 10.43
public void enableCallbacks() throws SaveInProgress, RestoreInProgress, RTIinternalError
{
featureNotSupported( "enableCallbacks()" );
helper.checkSave();
helper.checkRestore();
helper.getState().setCallbacksEnabled( true );
logger.debug( "enableCallbacks invoked(): callbacks turned on" );
}

// 10.44
public void disableCallbacks() throws SaveInProgress, RestoreInProgress, RTIinternalError
{
featureNotSupported( "disableCallbacks()" );
helper.checkSave();
helper.checkRestore();
helper.getState().setCallbacksEnabled( false );
logger.debug( "disableCallbacks invoked(): callbacks turned off" );
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
33 changes: 33 additions & 0 deletions codebase/src/java/portico/org/portico/lrc/LRC.java
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,10 @@ public void tick() throws JRTIinternalError, JConcurrentAccessAttempted
*/
public int tickUntilEmpty( long nanoWait ) throws JRTIinternalError, JConcurrentAccessAttempted
{
// don't process anything if callbacks aren't enabled
if( state.areCallbacksEnabled() == false )
return 0;

// check for a concurrent access issue
state.checkAccess();

Expand Down Expand Up @@ -516,6 +520,10 @@ public int tickUntilEmpty( long nanoWait ) throws JRTIinternalError, JConcurrent
public boolean tick( double minSeconds, double maxSeconds )
throws JRTIinternalError, JConcurrentAccessAttempted
{
// don't process anything if callbacks aren't enabled
if( state.areCallbacksEnabled() == false )
return true;

// check for a concurrent access issue
state.checkAccess();

Expand Down Expand Up @@ -570,6 +578,16 @@ public boolean tick( double minSeconds, double maxSeconds )
*/
public double tickFlush( double maxTime ) throws JRTIinternalError, JConcurrentAccessAttempted
{
// don't process anything if callbacks aren't enabled
if( state.areCallbacksEnabled() == false )
{
PorticoMessage next = state.messageQueue.peekTSO();
if( next != null && (next.getTimestamp() < maxTime) )
return next.getTimestamp();
else
return maxTime;
}

// check for a concurrent access issue
state.checkAccess();

Expand Down Expand Up @@ -615,6 +633,9 @@ public double tickFlush( double maxTime ) throws JRTIinternalError, JConcurrentA
*/
public boolean tickSingle( double wait ) throws JRTIinternalError, JConcurrentAccessAttempted
{
if( state.areCallbacksEnabled() == false )
return !state.messageQueue.isEmpty();

// check for a concurrent access issue
state.checkAccess();

Expand Down Expand Up @@ -776,6 +797,18 @@ public void run()
{
try
{
// If callbacks are currently not enabled, sleep for a bit and come back
// You mean just block!? Yes. I do. It's fine. Really. The stated use case
// for enabled/disable callbacks it to allow the federate to initiate a
// block on callbacks temporarily, so if unblocking takes a brief moment,
// it's really not an issue. Relax, tiger.
if( state.areCallbacksEnabled() == false )
{
Thread.sleep( 500 ); // sleep for half a second
continue;
}

// if callbacks are enabled, get bizzay processing them
PorticoMessage message = state.messageQueue.pollUntilNextMessage();

if( message != null )
Expand Down
12 changes: 12 additions & 0 deletions codebase/src/java/portico/org/portico/lrc/LRCState.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public class LRCState extends NullNotificationListener implements SaveRestoreTar
private TimeManager timeManager;
private TimeStatus timeStatus;
private boolean ticking;
private boolean callbacksEnabled;
private boolean immediateCallbacks;

// Pub&Sub settings //
Expand Down Expand Up @@ -172,6 +173,7 @@ protected void reinitialize()
this.timeManager = new TimeManager();
this.timeStatus = new TimeStatus(); // give us a dummy status with default values for now
this.ticking = false;
this.callbacksEnabled = true;
this.immediateCallbacks = false;

// Pub&Sub settings //
Expand Down Expand Up @@ -487,6 +489,16 @@ public void setFederationName( String federationName )
////////////////////////////////////////////////////////////
////////////////// Time Shortcut Settings //////////////////
////////////////////////////////////////////////////////////
public boolean areCallbacksEnabled()
{
return this.callbacksEnabled;
}

public void setCallbacksEnabled( boolean enabled )
{
this.callbacksEnabled = enabled;
}

public boolean isImmediateCallbackDeliveryEnabled()
{
return this.immediateCallbacks;
Expand Down
116 changes: 116 additions & 0 deletions codebase/src/java/test/hlaunit/ieee1516e/support/CallbacksTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2013 The Portico Project
*
* This file is part of portico.
*
* portico is free software; you can redistribute it and/or modify
* it under the terms of the Common Developer and Distribution License (CDDL)
* as published by Sun Microsystems. For more information see the LICENSE file.
*
* Use of this software is strictly AT YOUR OWN RISK!!!
* If something bad happens you do not have permission to come crying to me.
* (that goes for your lawyer as well)
*
*/
package hlaunit.ieee1516e.support;

import hlaunit.ieee1516e.common.Abstract1516eTest;
import hlaunit.ieee1516e.common.TestFederate;

import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
* This test covers the validation of the enableCallbacks() and disableCallbacks() services.
* <p/>
* This will be achieved by having a federate fire object update events that the default federate
* is interested in, along with validation that these are/aren't processed as appropriate.
*/
@Test(sequential=true, groups={"CallbacksTest", "callbacks", "supportServices"})
public class CallbacksTest extends Abstract1516eTest
{
//----------------------------------------------------------
// STATIC VARIABLES
//----------------------------------------------------------

//----------------------------------------------------------
// INSTANCE VARIABLES
//----------------------------------------------------------
private TestFederate secondFederate;

//----------------------------------------------------------
// CONSTRUCTORS
//----------------------------------------------------------

//----------------------------------------------------------
// INSTANCE METHODS
//----------------------------------------------------------
@Override
@BeforeClass(alwaysRun=true)
public void beforeClass()
{
super.beforeClass();
this.secondFederate = new TestFederate( "secondFederate", this );
}

@BeforeMethod(alwaysRun=true)
public void beforeMethod()
{
defaultFederate.quickCreate();
defaultFederate.quickJoin();
secondFederate.quickJoin();
}

@Override
@AfterClass(alwaysRun=true)
public void afterClass()
{
super.afterClass();
}

@AfterMethod(alwaysRun=true)
public void afterMethod()
{
secondFederate.quickResign();
defaultFederate.quickResign();
defaultFederate.quickDestroy();
}

//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Test Methods //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// TEST: testEnableDisableCallbacksWithAttributeUpdates() //
////////////////////////////////////////////////////////////
@Test
public void testEnableDisableCallbacksWithAttributeUpdates() throws Exception
{
// set up the publication and subscription interests
defaultFederate.quickPublish( "ObjectRoot.A", "aa" );
secondFederate.quickSubscribe( "ObjectRoot.A", "aa" );
int objectHandle = defaultFederate.quickRegister( "ObjectRoot.A" );
secondFederate.fedamb.waitForDiscovery( objectHandle );

// have the default federate update the object and ensure second federate receives
defaultFederate.quickReflect( objectHandle, "aa" );
secondFederate.fedamb.waitForROUpdate( objectHandle );

// disable callbacks and ensure updates don't get through
secondFederate.rtiamb.disableCallbacks();
defaultFederate.quickReflect( objectHandle, "aa" );
secondFederate.fedamb.waitForROUpdateTimeout( objectHandle );

// re-enable callback and make sure they get through
secondFederate.rtiamb.enableCallbacks();
defaultFederate.quickReflect( objectHandle, "aa" );
secondFederate.fedamb.waitForROUpdate( objectHandle );
}

//----------------------------------------------------------
// STATIC METHODS
//----------------------------------------------------------
}

0 comments on commit 76ce0e8

Please sign in to comment.