LRC Architectural Overview

The Local Runtime Component (LRC) is a piece of software that user federate code connects to in order to communicate with the RTI. It provides to clients the necessary implementations of all the standard types (such as ) and completes other tasks; such as ensuring callback messages are queued and released to the federate according to the requirements of the specification.

The Portico LRC includes three areas where extension or re-purposing can occur: Two message sinks and a communications binding. This document discusses the internal structures of the Portico LRC and how they work

Architectural Overview
The Portico LRC consists of a reasonably small number of classes and interfaces that a user must be comfortable with using. These types fall into two categories:


 * Framework Components: These are components that provide some consistent structure to the LRC and define the workflow employed within it. These are things like  and the.
 * State Components: There are components that are used by the default plug-ins to manage state information about the federate connected to the LRC.

Figure 1 is a graphical overview of the LRC structure.



There are several components to take note of in the diagram above:


 * The  and   entities
 * The
 * The
 * The
 * The
 * The

The purpose for each of these components and a basic introduction to how they operate is provided in the sections below. The process of configuring each of these components is discussed in the LRC Configuration document.

The and   Entities
The  class is the central component for the client side of the Portico framework. When a new  instance is created, so is a new   instance. Despite being of critical importance to the framework, by itself, it doesn't really do anything. Rather, it acts more as a container for the other LRC components that manage state and provide behaviour.

Two MessageSinks are contained in the LRC and it is the handlers inside them that provide the component with the necessary HLA behaviour.

The lrc-request Sink
As methods are called on the, they are turned into the appropriate Message instances and passed to the lrc-request sink for processing. If the request contains no errors*, then at some point the message is passed to the  to be sent to the RTI.

* Errors in this context are defined as HLA errors; such as trying to update attribute values while a federation save is in progress.

The lrc-callback Sink
When callback messages are received from the RTI, they are stored on the. At some later point, when user federate code calls  messages are released from this queue and passed into the lrc-callback sink. It is expected that the handlers of this sink will translate the messages into the appropriate  callbacks.

The class
The  component contains a link to most of the non-structural entities used by the LRC. On top of this, it also stores a bunch of other state information such as the federate name, handle, current time, status of time regulation and constrained, lookahead and so on. As long as a handler extends the  class, it will have automatic access to the state (and thus, all of these entities). See Writing Plugins for more information on this.

The  class also includes a generic   that user handlers can use to store values in. Rather than forcing a user handler to come up with their own storage class for information, they can use this map. If more complex storage options are required, custom classes will need to be created.

The Interface
The  is just a marker interface. It is the vessel through which the different  implementations in the   package access the. However, the interface was primarily created to deal with some of the differences that exist between the different HLA interface specifications.

Storing a link to a federate's  implementation is tricky. As each HLA interface API provides a different fully-qualified interface that must be implemented, there is no way to store it inside the  in a manner that is applicable to all specifications. Further, there are some differences in some semantics (such as the operation of  or   between the specifications. The   implementation makes sure the appropriate methods are called to handle this.

As  is just a marker interface, for it to be useful, user code needs a reference to the actual implementation class. This is generally only a consideration during callbacks. Although there is one set of default handlers for the lrc-request sink, regardless of specification, there is a separate set of handlers for the lrc-callback sink, depending on which version of the spec is in use. As each callback handler is specific to a particular HLA version, it knows what the implementation class of the  is, and as such, can cast to it.

For example, the following code is taken from the  class:

 // fetch the specification helper // ISpecHelper temp = lrc.getSpecHelper; if( temp instanceof Impl13Helper ) {	this.helper = (Impl13Helper)temp; } else {	throw new ConfigurationException(	   "Expecting org.portico.impl.hla13.Impl13Helper, got " + temp ); }

As that is the handler class specific to the HLA 1.3 specification, it knows that the helper should be of the type

The  will load the appropriate callback sink configuration file when the LRC is under construction.

The code do to this is as follows (from the  method in  ):

 //////////////////////////////////////////////////// // 1. load the default configuartion base modules // //////////////////////////////////////////////////// XMLSource baseSource = XMLPreprocessor.preprocess( LRCProperties.DEFAULT_BASE_MODULE ); ModuleGroup baseGroup = this.getModules( baseSource );

////////////////////////////////////////// // 2. load the version specific modules // ////////////////////////////////////////// String moduleFile = LRCProperties.DEFAULT_13_MODULE; if( theLRC.getHLAVersion == HLAVersion.JAVA1 ) {	moduleFile = LRCProperties.DEFAULT_JAVA1_MODULE; } if( theLRC.getHLAVersion == HLAVersion.HLA1516 ) {	moduleFile = LRCProperties.DEFAULT_1516_MODULE; }

// load the module XMLSource xsource = XMLPreprocessor.preprocess( moduleFile ); ModuleGroup verGroup = this.getModules( xsource );

// combine the groups // baseGroup.addModules( verGroup.getAllModules );

////////////////////////////////////// // 3. configure the module handlers // ////////////////////////////////////// Bag additional = new Bag; additional.put( LRC.KEY_LRC, theLRC ); baseGroup.applyGroup(additional, theLRC.getRequestSink, theLRC.getCallbackSink);

The  class contains an instance variable of type. This variable is set by the  when it creates the LRC, and the spec helper knows which interface API it is providing.

The Creation Process
The actual  implementations don't generally maintain a direct reference to their associated   instance (although they could). Rather, they create a version of the appropriate  class and it in turn created the. Figure 2 shows this process when the HLA 1.3 API is being used:



This allows the  to make sure things are set up appropriate for the particular interface requirements of the API in use.

The
The  class is the facade for the connection that exists between the LRC and the RTI. Portico is said to be "communications protocol neutral," and it is the  that helps achieve this. All communication semantics are hidden behind this facade (and another one on the RTI side). When the LRC needs to send a message to the RTI, it simply invokes the  method on the connection, and the underlying implementation should transmit the request to the RTI via the appropriate mechanism.

The  class is abstract. All communications bindings need to provide a concrete subclass that implements the abstract,   and   methods in the appropriate manner for the communications mechanism in use. There are no other abstract methods of the class.

When a callback is received from the RTI via whatever communications protocol/facility is being used, the implementation should invoke the inherited  OR the   method. Either method is fine as they both do the same thing. These methods will take the callback and place it onto the  so that it can be processed later on when the federate is ready (as signified by a call to  ).

Connection Creation
During the configuration process for the LRC (as conducted by the ), a   implementation will be instantiated and stored inside the. The actual class that is instantiated depends on the value of the system property with the key.

If that property is NOT set, the default value as stored in  is used (currently, this is the   class). If that property IS set, the value is used.

A user can change the method used to connect to the RTI by changing that property to contain the fully-qualified name of a concrete class that extends. Note that the class it points to must have a public, no-argument constructor. See Writing Bindings for more information.

The
The  class stores the various publication and subscription interests that have been declared by the federate. For example, when a federate calls, the appropriate message handler for that call can store the preference for later use by calling the  's   method.

The interest manager also provides helper methods to quickly determine the publication or subscription status of a particular object, attribute or interaction class. This information is used by many other handlers in the framework. For example, when attempting to register an object instance, the handler will first check that the object class has been recorded as being published.

The interest manager resides in the  instance for the LRC. Any handler class that extends  will also have access to an inherited variable called   that points to the manager.

For more information, see the javadoc for the.

The
As objects are created and discovered by a federate, they need to be kept track of. This way, when the federate attempts to update an attribute, or delete an instance, the LRC can validate that the action can be taken without having to contact the RTI (for example, it can ensure all the appropriate permission and ownership requirements are met).

The  class is responsible for managing this information. Its interface is quite simple, providing basic methods to add and remove instance information, in addition to some helper methods that allow handlers to make quick determinations about a situation (e.g.  checks to see if the federate connected to the LRC owns any attributes at all - this is used when a federate is attempting to resign from a federation).

As with the LRCInterestManager, the LRCInstanceRepository instance for a federate resides in the LRCState. Any handler that extends  has access to an inherited variable called   that is a reference to the appropriate repository instance.

The and   classes
In other discussions about the role of the Object Model shared classes, no mention was made of the  or   classes. These two types provide an abstraction for object and attribute instances. They contain state information (such as the owner of the attribute or the name of the object) and a link to the metadata class that they are an instance of. They do not store any actual user-supplied data value (the values that federates give to attributes).

The
When a callback is received in an LRCConnection, it should be passed to one of the inherited  methods. These methods just throw the request onto the  (via the    method). This class is responsible for providing queue-like behaviour that conforms to the requirements of the HLA.

To call the LRCQueue a "queue" is a bit of a misnomer, as it is actually two queues. One queue is for receive ordered messages (RO), and the other for timestamp ordered messages (TSO). When the user calls, the queue will be drained (as much as possible) and passed to the lrc-callback sink for actual processing.

Removing messages from the LRCQueue isn't quite as simple as putting them in there in the first place. The basic algorithm followed by the queue when asked to fetch the next available message is defined in the following psudeo code:

 if( an RO message is queued ) {	if( federate is constrained && asynchronous delivery is NOT enabled ) {		if( federate has outstanding time advance request ) {			// if async delivery is NOT enabled (the default) *and* the // federate is constrained, only release the message if there // is currently a time advance request outstanding return RO message }	}	else {		// is async delivery is enabled, or the federate isn't constrained // just release the message now return RO message } } else if( a TSO message is queued ) {	double timestamp = peek at next TSO message if( timestamp is <= current federate time ) {		// if the timestamp of the next message is less than the current // federate time, release it. The current federate time is defined // as the last time to which the federate requested a time advance return TSO message } } else {	// if none of these conditions are met, don't release anything return null }

Handling Timestamp Order Messages
When a RO message is queued, it is added to the queue in the order it arrived. However, TSO messages are always kept in order, so the queue always remains sorted by timestamp (lowest to highest).

When a TSO message is received by a federate that is not constrained (and thus doesn't care about receiving messages in TSO), the timestamp is removed from the request and it is added to the RO queue. If, at any point, a federate goes from being constrained to unconstrained, the queue must be notified, and all the messages in the TSO queue will be removed and added to the RO queue.

For the most part, you don't need to worry about the LRCQueue. All you need to know is that it will only release to you messages that are safe to process. If you would like to know some more about the queue, you can see the javadoc for the class, or take a look at the code.

Writing LRC Message Handler Plugins
The general process and requirements for writing Message Handler plug-ins for the lrc-request or lrc-callback sinks is the same as for writing any other message handler plug-ins.

However, Portico does provide a special abstract parent class that all handlers should extend. This class is the class. Although this is not mandatory, the parent class will provide a handler with a number of convenience methods and access to useful inherited variables that point to commons LRC components.

See the javadoc for additional details, or if you want an example of what a handler should look like, see the code for any of the classes in the  package. Alternatively, the listing below provides a simple template that can be used for message handlers:

 import com.lbf.commons.config.ConfigurationException; import com.lbf.commons.messaging.MessageContext; import com.lbf.commons.utils.Bag;

import org.portico.lrc.handlers.LRCMessageHandler;

/** * A description of the purpose and behaviuor of the handler */ public class MyLrcHandler extends LRCMessageHandler {   //--    //                    STATIC VARIABLES //--

//--   //                   INSTANCE VARIABLES //--

//--   //                      CONSTRUCTORS //--

public MyLrcHandler {       super( "MyLrcHandler" ); }   //--    //                    INSTANCE METHODS //--   public void initialize( Bag properties ) throws ConfigurationException {       // run the super initializer // super.initialize( properties ); }   /**     * A description of the main processing this handler will do when invoked */   public void processMessage( MessageContext context ) throws Exception {       logger.error( "MyExampleHandler doesn't do anything yet!!" ); // insert a success response into the context success( context ); }   //--    //                     STATIC METHODS //-- }

Writing an LRC Callback Handler
Although you can write an LRC callback handler just like any other Message Handler, the process taken by the default plugins for Portico is different.

The main problem is that the  class for each version of the specification is different, and as such, requires different handling. Rather than writing a bunch of callback handlers, and then writing different versions of them for each different version of the interface specification, Portico provides only one callback handler for each interface version (and it resides in the appropriate impl package).

This handler is configurable through XML to take the type of messages to be handled, and identify the method within the class that should be called when that message is received. Depending on which interface is in use, the proper XML configuration file is loaded when an LRC is created. Below is an example of the file for the standard HLA 1.3 interface:

  lrc-modules(1.3) 1.0        The Portico Porject



      <message id="FED_SyncPointAnnounced"/> <message id="FED_SyncPointRegResult"/> <message id="FED_Synchronized"/> <message id="FED_DiscoverObject"/> <message id="FED_RemoveObject"/> <message id="FED_ReceiveInteraction"/> <message id="FED_ReflectAttributes"/> <message id="FED_ProvideUpdate"/> <link id="FED_AdvanceGranted" method="timeAdvanceGranted"/> <link id="FED_ConstrainedEnabled" method="constrainedEnabled"/> <link id="FED_RegulationEnabled" method="regulationEnabled"/> <link id="FED_SyncPointAnnounced" method="syncPointAnnounced"/> <link id="FED_SyncPointRegResult" method="syncPointRegResult"/> <link id="FED_Synchronized" method="federationSynchronized"/> <link id="FED_DiscoverObject" method="discoverObject"/> <link id="FED_RemoveObject" method="removeObject"/> <link id="FED_ReceiveInteraction" method = "receiveInteraction"/> <link id="FED_ReflectAttributes" method="reflectAttributes"/> <link id="FED_ProvideUpdate" method="provideUpdate"/>

You can see in this file that a separate module is declared, and that only a single handler exists in the callback sink (with no handlers in the request sink). If you wanted to extend this callback handler to process new callbacks (as the Portico developers do from time-to-time) you would need to do the following:


 * Add an appropriate method to the callback class (in this case )
 * Edit the appropriate XML configuration file (all files are located in the  directory in the source repository. See Source Code for more information on how to access the source.
 * Add the line:  pointing to the appropriate message class. If the package-alias is not set, this must be the fully-qualified name of the message class (see  for more details)
 * Add the link:  Where   is the message class and   points to the name of the method you added

Important Considerations for Extensions and Plug-ins
The default plug-ins provided with the Portico LRC are designed to operate as efficiently as possible in a true client/server architecture. That is, all the filtering algorithms and processes employed work on the assumption that the main intelligence lies in the RTI.

For example, the LRC will happily accept all incoming callback messages, regardless of whether or not the  property points to the federate that LRC is attached to. In the context of the current client/server implementation, this is not a concern, because messages are only ever routed to the appropriate LRCs. However, if one were to implement a more distributed communications binding, where callbacks are multicast, the LRC handlers would need to provide more filtering.

Consider a situation where attribute value updates are multicast rather than filtered on the server and then forwarded on to the appropriate federates. In this situation, the LRC would need to filter incoming messages to see if there are any attributes that the federate has an interest in (and thus, would need to consult the ). However, the multicast property is really a facility of the communications binding, while the filtering would generally be handled by a Message Handler.

Another example lies in the default state-management components used by the LRC. These entities are only relevant because the default handlers make use of them. If the handlers were to start using other classes to manage state, the current classes would become useless. However, before designing your own plug-ins that make use of entirely new components, remember that other handlers may be depending on the entities that you are no longer using. Without the proper information flowing in there, other parts of the RTI may break. For example, if the publish and subscribe handlers started using a new class to manager their interests, the handlers processing attribute update requests would fail, because they would be looking in the old component and would not see that the federate was indeed publishing the attributes it was trying to update.

Through these examples you can see that even though the Portico framework is designed to be modular and flexible, there are many situations in which forethought about how new or altered code will affect other functionality is needed. Whether is be changes at the same level (handler changes affecting other handlers) or at different levels (communications bindings affecting handlers), when designing plug-ins, a more holistic mindset should be employed. Think about what you are trying to achieve and how that might affect the behaviour of the RTI given the way the default components work.