copyright The Portico Project 2008.

org.portico.lrc
Class LRC

java.lang.Object
  extended by org.portico.lrc.LRC

public class LRC
extends Object

This class represents the core the Portico local runtime component. It contains the various message sinks that process incoming and outgoing messages, in addition to all the state data regarding a particular federate and the communications binding connection over which it can send messages so that they reach the RTI.

Messaging and Behaviour

The LRC includes two MessageSinks that perform processing on messages that are travelling to and from the RTI. These sinks are briefly described below:

Threading and Queues

The LRC includes an instance of the LRCQueue class. As callback messages are received from the RTI, they are placed on this queue. The LRCQueue imeplements special release semantics depending on the status of the message (TSO/RO) and the current status of the federate. When a federate starts evoking callbacks, these messages are retrieved and passed to the lrc-callback sink for processing (note: callbacks are not processed as they are received).

As such, the LRC should generally only require a single thread. This is the same thread that is running the federate. When the federate invokes RTIambassador calls, the messages are created and dropped into the lrc-request sink where they can be processed and sent to the RTI. The federate then blocks until the RTI responds (not a callback). When the federate is ready for callbacks to be received, they invoke tick() (or evokeCallbacks(), or whatever) and the tick method will take messages from the LRCQueue and pass them to the lrc-callback sink which in turn should see them delivered to the federate. This all happens while the federate is blocked on the tick call.

While the main processing of the RTI does not require a thread of its own (it just uses the federate thread), depending on the communications binding and active plugins that have been deployed, other threads may be started. Fore example, the JSOP bindings need a separate thread to service the socket connection, listening all the time for incoming callback messages. When it received one, it puts it on the LRCQueue, thus populating it without disturbing the main thread. There may also be plugins that start other services that themselves require additional threads. The important thing to note is that you cannot guarantee that the LRC will only use a certain amount of threads without knowing the threading requirements of the binding in question and any additional plugins that will be deployed.

LRC State

All LRC state data is stored in the LRCState instance that is contained within every LRC. Rather than pollute the LRC class with a bunch of state data, it was factored out into a dedicated data-object. The LRCState also includes links to other data storing entities such as the LRCInstanceRepository which contains a cache of all object related information that a particular federate knows about. See the LRCState javadoc for more information.

LRC Connection

The communications portion of Portico is communications binding neutral. As such, the actual classes that perform the communications between an LRC and the RTI (and the protocol they implement) are totally hidden from the LRC. When the LRCConfigurator configures an LRC instance, it consults a number of potential sources to determine the fully-qualified name of the LRCConnection subclass that should be used to perform the communications with the RTI. The LRC stores a reference to this instance and it is used to send/receive messages from the RTI in its own implementation-specific manner.

Specification Difference Handling

The various HLA specifications contain a large amount of incompatible elements (primarily, exception types). For whatever reason, actual API compatibility does not appear to have been considered during the specification process. To get around this, the LRC, like the rest of Portico, uses a special "compatibility" layer. These classes are housed within the org.portico.shared.compat package and constitute a general group of exception types and other related classes. Throughout all the handlers and other components within Portico, these types, and ONLY these types should be used. At the very last minute they are mapped onto the appropriate specification-specific equivalents.

To help with some other specification-specific tasks, each LRC has an ISpecHelper implemenation. There is an implementation for each specification and it maintains a bunch of specification dependant entities and tasks.


Nested Class Summary
private  class LRC.LRCDefaultCallbackHandler
          This class will act as the default handler for the lrc-callback message sink.
private  class LRC.LRCDefaultRequestHandler
          This will act as the default handler for the lrc-request MessageSink.
 
Field Summary
protected  org.apache.log4j.Logger callbackLogger
           
protected  LRCQueue callbackQueue
           
protected  com.lbf.commons.messaging.MessageSink callbackSink
           
protected  LRCConnection connection
           
protected  ISpecHelper helper
           
static String KEY_LRC
          When the LRC is put in Bags/Maps, this is the key that should be used to identify it
protected  org.apache.log4j.Logger logger
           
protected  com.lbf.commons.messaging.MessageSink requestSink
           
protected  LRCState state
           
protected  HLAVersion version
           
 
Constructor Summary
LRC(HLAVersion version, ISpecHelper helper)
          Create a new instance of the LRC that is targeted at the given HLAVersion and that should use the provided ISpecHelper.
 
Method Summary
 org.apache.log4j.Logger getCallbackLogger()
           
 LRCQueue getCallbackQueue()
           
 com.lbf.commons.messaging.MessageSink getCallbackSink()
           
 HLAVersion getHLAVersion()
           
 LRCConnection getLRCConnection()
           
 org.apache.log4j.Logger getLRCLogger()
           
 LRCState getLRCState()
           
 com.lbf.commons.messaging.MessageSink getRequestSink()
           
 ISpecHelper getSpecHelper()
          Fetches the current specification-specific helper.
 void reinitialize()
          Cleans the entire LRC of all state and sets it up as new.
 void setLRCConnection(LRCConnection connection)
           
 void setSpecHelper(ISpecHelper helper)
           
 void tick()
          This method will take some time to poll for any messages waiting to be processed in the LRC.
 boolean tick(double min, double max)
          Process the callback queue for the given amount of time (in seconds).
private  boolean tickNanos(long nanos)
          Do some tick processing at least the given amount of time (in nanoseconds).
private  boolean tickNanosSingle(long timeout)
          This tick() implementation is meant to support the 1516-style evoke single callback facility.
private  void tickProcess(FED_CallbackMessage message)
          Passes the given message to the callback sink (wrapped up in a context)
 boolean tickSingle(double wait)
          Try and process a single callback.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

KEY_LRC

public static final String KEY_LRC
When the LRC is put in Bags/Maps, this is the key that should be used to identify it

See Also:
Constant Field Values

requestSink

protected com.lbf.commons.messaging.MessageSink requestSink

callbackSink

protected com.lbf.commons.messaging.MessageSink callbackSink

callbackQueue

protected LRCQueue callbackQueue

state

protected LRCState state

version

protected HLAVersion version

helper

protected ISpecHelper helper

connection

protected LRCConnection connection

logger

protected org.apache.log4j.Logger logger

callbackLogger

protected org.apache.log4j.Logger callbackLogger
Constructor Detail

LRC

public LRC(HLAVersion version,
           ISpecHelper helper)
    throws JRTIinternalError
Create a new instance of the LRC that is targeted at the given HLAVersion and that should use the provided ISpecHelper. This method will call reinitialize() before it returns in order to set up and configure the LRC. If there is a problem with this process (for example, the configuration file contains an error) then a JRTIinternalError will be thrown.

Throws:
JRTIinternalError
Method Detail

reinitialize

public void reinitialize()
                  throws JRTIinternalError
Cleans the entire LRC of all state and sets it up as new. This method should only be used when the LRC is first being constructed, and when it has resigned from a federation (so that when it rejoins, it can do so with a clean state).

This method will first wipe clean all the information in the linked LRCState instance before creating new instances of the various message sinks and the LRCQueue (to ensure that there are no left-over callbacks left for processing).

After this, the LRC is passed to the LRCConfigurator where the configuration file is applied to it, along with the configurations from the various plugins that have been deployed. If any of this causes an error, a JRTIinternalError will be thrown.

Throws:
JRTIinternalError

tick

public void tick()
          throws JRTIinternalError,
                 JConcurrentAccessAttempted
This method will take some time to poll for any messages waiting to be processed in the LRC. Previously, if there was no work to do, it would just return right away. However, this lead to instances where the CPU was put under undue load as simulation code just continued to tick away until some condition changed as a result of a message finally being available for processing (for example, there would be something like 2 million calls to tick() for 1000 time advances in some cases with the RMI binding). To prevent this problem, the algorithm used by this method is as follows:
  1. Check for a message, waiting for at most LRCProperties.LRC_TICK_TIMEOUT if there is nothing to process
  2. If there is still no work after the above, just return
  3. If we get a message, process it and return

Throws:
JRTIinternalError
JConcurrentAccessAttempted

tick

public boolean tick(double min,
                    double max)
             throws JRTIinternalError,
                    JConcurrentAccessAttempted
Process the callback queue for the given amount of time (in seconds). Wait at least as long as the given minimum time and keep processing messages up until the maximum time at most.

Note: The current implementation ignores the minimum value, processing as many messages as possible up until the max time. If there are no messages, it will wait as long as the max time.

Returns:
Return true if there are more messages waiting to be processed, false otherwise
Throws:
JRTIinternalError
JConcurrentAccessAttempted

tickSingle

public boolean tickSingle(double wait)
                   throws JRTIinternalError,
                          JConcurrentAccessAttempted
Try and process a single callback. Once a single callback has been processed return. If there are no callbacks to process, waiting as long as the given time (in seconds) before giving up. Return true if there are more messages waiting to be processed, false if there are not.

Parameters:
wait - The time to wait for a single message to be received (in seconds)
Returns:
True if there are more messages waiting to be processed, false otherwise
Throws:
JRTIinternalError
JConcurrentAccessAttempted

tickNanos

private boolean tickNanos(long nanos)
                   throws JRTIinternalError
Do some tick processing at least the given amount of time (in nanoseconds). This method will return true if at least one message was processed in the given time, false otherwise.

Throws:
JRTIinternalError

tickNanosSingle

private boolean tickNanosSingle(long timeout)
                         throws JRTIinternalError
This tick() implementation is meant to support the 1516-style evoke single callback facility. It will only process a SINGLE callback. If there is none available, it will wait at most until the given time out. Once the timeout has expired or a single callback has been processed, it will return: true if there are more callbacks available for processing, or false if there are no more callbacks.

Parameters:
timeout - The time in nanoseconds to wait for a callback if there is not currently one available.
Returns:
True if there are more callbacks waiting, false if there are none
Throws:
JRTIinternalError - If there is a problem processing the callbacks

tickProcess

private void tickProcess(FED_CallbackMessage message)
                  throws JRTIinternalError
Passes the given message to the callback sink (wrapped up in a context)

Throws:
JRTIinternalError

getLRCConnection

public LRCConnection getLRCConnection()

setLRCConnection

public void setLRCConnection(LRCConnection connection)

getLRCState

public LRCState getLRCState()

getHLAVersion

public HLAVersion getHLAVersion()

getRequestSink

public com.lbf.commons.messaging.MessageSink getRequestSink()

getCallbackSink

public com.lbf.commons.messaging.MessageSink getCallbackSink()

getCallbackQueue

public LRCQueue getCallbackQueue()

getLRCLogger

public org.apache.log4j.Logger getLRCLogger()

getCallbackLogger

public org.apache.log4j.Logger getCallbackLogger()

getSpecHelper

public ISpecHelper getSpecHelper()
Fetches the current specification-specific helper. If this is a 1.3 federate, the helper should come from the 1.3-specific implementation classes. If it is 1516, obviously it should come from the 1516-specific implementation classes. The spec helper contains access to specification version specific values (such as FederateAmbassadors and the like).


setSpecHelper

public void setSpecHelper(ISpecHelper helper)

copyright The Portico Project 2008.