General Java Porting Principles


The primary aim of this project is to port the prototype framework developed in the AOCS Framework Project from C++ to Java. This page describes the general principles that guided and constrained the porting process.


Adherence to C++ Version

A software framework as conceptualized in this project consists of three types of constructs : The overall objective of the porting exercise is to maintain as far as possible consistency with the C++ version of the framework at the levels of design, architecture, and implementation. Thus, the default rules applied in porting each of the above constructs are as follows: These rules could not be followed in all cases. Differences between C++ and Java, uncertainties about the real-time Java specifications, a desire to take advantage of the JavaBeans standard made it sometimes necessary to deviate from the original C++ design and implementation of the framework. The types of deviations that were necessary are discussed below in this page.

Back To Top, Back to Real-Time Java Project Home


Minor Changes

Minor changes were made both to fix small design bugs in the C++ version of the framework, to adapt the code to the naming convention mandated by the JavaBeans standard (see point below), and to obviate to the lack of constructs like typedef in Java. Minor changes that are localized to specific methods or classes in the framework are listed in the table:
 
Class/Method Affected
Change Description
Runnable Class name was changed to ActiveObject to avoid conflict with Java Runnable class and because the framework runnable object concept coincides with the active object of HRT-HOOD
AocsObject.reportFailure Parameter creator was dropped (it was never used in C++ version)
AocsObject.reportConfigurationError Parameter creator was dropped (it was never used in C++ version)
AocsObject.reportConfigurationError Method name was changed to: reportConfigurationEvent
*.initialize, 
*.allocateMemory
These initialization methods in components are changed to setter method in the spirit of the JavaBeans architecture. For instance, method ObjectList.allocateMemory is renamed to setSize where size now represents one of the properties of object lists. Similarly, method SystemManager.initialize is replaced by a setter methods for each of its parameters that are now treated as JavaBeans properties.
EventList.setList Method name is changed to setEvent
AocsDataPool.configureDataList Method name is changed to setDataPoolSize where the data pool size is now treated as a JavaBeans property
ObjectList.first, 
ObjectList.next, 
ObjectList.getObjectByPosition
Method names changed to firstObject, nextObject, getByPosition (see below for the reason of this change).
AocsData.Close(double,double) Method removed as redundant
SystemManager.add Method name changed to addAocsObject (for reasons of clarity)
SystemManager.remove Method name changed to removeAocsObject (for reasons of clarity)
SystemManager.loadConfigurations Method name changed to restoreConfiguration (for reasons of naming consistency)
ModeManager.inhibitMode Method name changed to disableMode (for reasons of naming consistency)
FollowerModeManager Parameter numberOfModes in the constructor was dropped as redundant (the number of modes is the same as the number of modes in the master mode manager)
RecoveryAction.enable, 
RecoveryAction.disable
Methods replaced by a single setEnabled method (for consistency with JavaBeans model)
RecoveryStrategy.enable, 
RecoveryAction.disable
Methods replaced by a single setEnabled method (for consistency with JavaBeans model)
RecoveryStrategy The failure event repository is now a settable parameter for class RecoveryStrategy. This is because, with the new event model, there may be several failure event repositories in the same application.
AocsMissionModeManager Removed method loadImplementers which behaved differently from the C++ version due to the different dynamical binding model.
Telecommand.execute The set of return codes of this method has been modified. Return code TC_FAILURE has been replaced with the codes TC_FAIL_SAFE and TC_FAIL_UNSAFE. See the documentation in class TelecommandCodes.
Telecommand.enable, 
Telecommand.disable
Methods replaced by a single setEnabled method (for consistency with JavaBeans model)
Telecommand.getNumberOfTelecommands Method name changed to getNumberOfPendingTelecommands
Manoeuvre.putInUse, Manoeuvre.unUse Methods replaced by setInUse for consistency with JavaBeans property model
Manoeuvre.AddManoeuvreManager,
Manoeuvre.RemoveManoeuvreManager,
Methods were removed since they were not implemented in the C++ version of the framework (they represent a possible future extension of the framework which is no longer judged interesting)
AbstractControlChannel Class implements the interfaces DataSource and DataSink, in reality the methods getOutput(int i), getNumberOfOutputs(), setInput(double newValue, int i), getNumberOfInputs().
AbstractControlChannel.setInputOrder Method was replaced by: setNumberOfInputs
AbstractControlChannel.setOutputOrder Method was replaced by: setNumberOfOutputs
AbstractControlChannel.getInputOrder Method was replaced by: getNumberOfInputs
AbstractControlChannel.getOutputOrder Method was replaced by: getNumberOfOutputs
AbstractControlChannel.hold Method was replaced by: setOnHold
AbstractControlChannel.release Method was replaced by: setOnHold
AbstractControlChannel.linkInput
(DataItemRead d, int j)
Method was replaced by: linkInput(DataSource d, int j). DataSource is a component presenting a fixed number of outputs from which data can be read.
AbstractControlChannel.linkInput
(AbstractControlChannel* c, int i, int j)
Method was replaced by: linkInput(DataSource c, int i, int j). DataSource is a component presenting a fixed number of outputs from which data can be read.
ControlChannelBlock Class implements all inhereted abstract methods from the class AbstractControlChannel and implements methods defined in interfaces DataSource and DataSink.
ControlChannelBlock.setStateOrder Method was replaced by: setNumberOfStates
ControlChannelBlock.getStateOrder Method was replaced by: getNumberOfStates
ControlChannelBlock.hold Method was replaced by: setOnHold
ControlChannelBlock.release Method was replaced by: setOnHold
ControlChannelBlock.allocateMemory The memory initialization method is changed to setter methods in the spirit of the JavaBeans architecture. The mehod ControlChannelBlock.allocateMemory is spilt into setInputSize, setOutputSize, and setStateSize. As a complement to these setter method is introduced a new method called resetMemory() that performs the memory reset.
ControlChannelSuperBlock Class implements all inherited abstract methods from the class AbstractControlChannel and implements methods defined in interfaces DataSource and DataSink.
DataItemRead and DataItemWrite DataItemRead and DataItemWrite objects encapsulates a reference to the data source or data sink. This mechanisms is used internally.
IoLink The structure IoLink implemented in the class ControlChannelSuperBlock was rewritten into individual class.

The non-localized minor changes are:

Back To Top, Back to Real-Time Java Project Home

Package Architecture 

The top-level package for the framework classes is RtjAocsFramework. This package contains a number of subpackages that match the subdirectories of the Visual Studio project where the C++ version of the framework was developed.

Back To Top, Back to Real-Time Java Project Home


Use of Templates 

The C++ version of the framework used templates only to specialize the ObjectListTemplate class. The templatized classes were simply providing a type-safe wrapper for the ObjectList class. In the Java version of the framework, the template mechanism was replaced by the inheritance mechanism. The class ObjectList is functionally the same as in the C++ version of the framework. Type-safety is achieved by providing derived classes that expose type-safe methods to access the items in the object list. The names of the derived classes are as follows: <type-name>List is the wrapper that provides a type-safe list of objects of type <type-name>.

One awkward consequence of this approach is that methods like first in class ObjectList would now appear both in ObjectList and in its derived classes with different return types. This is forbidden by the Java compiler and therefore it was necessary to change the name of ObjectList.first to ObjectList.firstObject. Similar changes, and for the same reasons, were made to methods next and getObjectByPosition (see list of minor changes above).

Back To Top, Back to Real-Time Java Project Home


Synchronization and Scheduling Issues

The framework components are designed to be used in a multi-threading environment. The framework components can be divided into two categories with respect to scheduling and synchronization issues:

In a typical instantiation, to each active component, a dedicated thread is associated. How the threads are scheduled is an instantiation issue. The active components defined by the framework are written to be independent of how often they are activated and of the order in which they are activated. In a typical instantiation, all the active components are scheduled in accordance with a cyclical policy with the possible exception of the TelecommandLoader component that may be treated as a sporadic component to be awakened by the arrival of a new telecommand. Note however that this is not always the case. In some applications, the telecommand loader may be implemented to be activated cyclically to process raw telecommand data that are accumulated in a buffer by a lower level task (e.g. an interrupt processing routine).

Operation in a multithreading environment requires the implementation of mechanisms to preserve data integrity. This is done at three levels. At the first integrity level, it is necessary to ensure that objects are accessed in mutual exclusion. Consider the following method call:

    a.method(...);

The implementation of the method might change the internal state of object a and therefore this method call can only be guaranteed to be thread-safe if its execution is not interrupted by other threads that perform operations on object a. In the AOCS Framework, this objective is achieved by marking all methods that may be called during the operational phase synchronized. The only methods that are not subjected to this precaution are the configuration or initialization methods. These are methods that are intended to be called only during the application initialization phase when multi-threading operation has not yet begun. Typical configuration methods are: resetConfiguration and isConfigured. Other configuration methods are identified as such in the method documentation.

At the second integrity level,  it is necessary to ensure that data that are acquired from the same objects through separate operations are consistent. Consider the following situation:

     v1 = a.method1(...);

    v2 = a.method2(...);

    . . .    // process v1 and v2

Suppose that there is a requirement that the two return values v1 and v2 are mutually consistent in the sense that, while they are acquired, the state of object a is not altered. There are two cases where this situation arises in the framework:

In a non-real-time environment, the simplest way to cope with the above problem would be for the processing code to clone object a and thus create an internal copy that can be processed in the absence of interference from other threads (NB: this approach only works if the clone method is implemented as a synchronized method). However, creating internal clones requires performing a dynamic memory allocation which is not compatible with hard real-time constraints. Hence, the solution adopted in the framework is as follows:

    synchronized (a) {

           v1 = a.method1(...);

        v2 = a.method2(...);

    }

    . . .    // process v1 and v2

The acquisition operations are enclosed in a synchronized block that ensures that the state of the object from which the data are acquired is not altered by other threads. Thus, the solution to the two examples listed above is:

At the third integrity level,  it is necessary to ensure that data acquired from several sources are consistent. A typical example is the processing of sensor data by the controller. Consider for instance a situation where a controller processes data from two different sensors and produces data for two different actuators. Clearly, if the sensor acquisition task is interleaved with the control processing task and the latter is in turn interleaved with the actuator commanding task, a situation may arise where the controller takes as input data that have been acquired from the two sensors at different times or, similarly, a situation may arise where the actuators receive commands that have been computed in two different cycles. 

The framework takes the view that this kind of integrity issues must be dealt with at application design level. Normally, this would be done by defining a scheduling policy that ensures that the tasks that produce certain data have terminated their execution before the task that processes those data can begin. Thus, in the example situation outlined above, one would assign a release time for the controller task that is later than the deadline for the sensor acquisition task, and a release time for the actuator commanding task that is later than the deadline for the controller task. 

Back To Top, Back to Real-Time Java Project Home


Dynamic Binding Model

There are some subtle differences between the Java and C++ dynamic binding model (at least, as they are implemented, respectively, by the VisualStudio and JBuilder compilers). Consider a class A that defines two public method f() and g() and suppose that g() calls f(). Consider now a second class B that overrides method f(). When B.g() is executed, which version of f() is called? In C++, it may be the version defined by class A whereas in Java it is the new version defined by class B. In general, in Java, an overridden method is no longer accessible.

This difference made the following changes necessary in the Java version of the framework:

Back To Top, Back to Real-Time Java Project Home

Compliance with Real-Time Java Specifications

There are at present two specifications for real-time Java. The first is proposed by the Java expert group and the second by the J-Consortium. The former is generally regarded as having the greatest chance of dominating the market and is therefore baselined as the target. On the other hand, there is some uncertainty about the stability of these specifications and even greater uncertainty about the extent to which they are implemented in JVM currently on the market. In order to mininimize the impact of such uncrtainty, the Java framework is designed to be independent of any RT-specific aspects of Java.

Some of the code in a complete application is directly or indirectly inherited from the framework. This includes the components supplied by the framework, code that implements framework-supplied abstract interfaces, and code that supports framework-supplied design patterns. The framework is designed in such a manner that this code only uses standard Java constructs. This makes the framework compatible with different variants of real-time Java but also imposes the following restrictions on the design and implementation of the framework:

The RT-dependent part of an application is built around the framework, typically in the threads that control the activation of the framework active objects.

Back To Top, Back to Real-Time Java Project Home


Components as Java Beans

For reasons explained elsewhere, it is intended to package all framework components as Java beans. This had the following repercussions: Back To Top, Back to Real-Time Java Project Home

The Framework Event Model

The event model of the framework was modified as part of the transformation of the framework components into Java beans. The objective was to implement the framework event mechanism in a manner that is compatible with the Java beans event model. Compatibility was achieved at the syntactical and at the naming level. This is important to ensure that the framework events can be manipulated by standard beanbox environments. The usage of events in the framework, however, differs from the ordinary usage of events in Java beans applications. In particular, Java applications typically create an event dynamically before firing it. This is not possible in the framework where dynamic creation of objects is not allowed. The adopted model hence is as follows. Event sources maintain a dummy event object. When they need to fire an event, they load the event parameters into the dummy event and pass the latter to the fireEvent method. The event listener begins the processing of the incoming event by copying its parameters into an internal data structure. This releases the dummy event in the event source for use in the next event firing operation. In order to avoid data corruption in a multithreading environment, the copying of the event parameters to the internal data structure is done in a synchronized section.

A second implication of the adherence to the Java beans event model is that class the AocsEvent class is implemented in the Java version of the framework as a subclass of EventObject. It is therefore the only framework class that does not inherit from RootObject. The constructor of class EventObject requires the event source as an argument and treats it as read-only parameters. This is not adequate for the framework that requires all event parameters to be settable since events cannot be created dynamically. Hence, the framework passes to the constructor of EventObject a dummy argument that is never used. The event source is stored as a parameter defined by class AocsEvent.

In the C++ version of the framework, events are generated to be stored in event repositories. In the Java version therefore the event repositories become event listeners. In one important difference with the C++ version of the framework, each event source could fire events to only one event repository. In the Java version, instead, event sources maintain an array of event listeners and can therefore potentially send their events to multiple repositories. Thus, for instance, it would be possible to have two failure event repositories.

Event adapters are not used in the Java framework. This is because it is assumed that event processing is "quick" and can therefore be done in the thread of the event source.

Back To Top, Back to Real-Time Java Project Home


Management of Configuration Information

In the C++ version of the framework, reconfigurable objects notify the system manager every time their configuration changes by calling dedicated methods exposed by class SystemManager. In the Java version of the framework the notification of configuration changes is done through events. Reconfigurable objects act as sources of reconfiguration events. The system manager is a listener to reconfiguration events. The system manager must register with reconfigurable objects during the initialization phase and will then be automatically notified whenever there are configuration changes.

Back To Top, Back to Real-Time Java Project Home


Linking Data Flow Components

In the C++ version of the framework, data flow components (namely components that cyclically produce data outputs or require data inputs) were linked to their data sources and data sinks through DataItemRead and DataItemWrite objects. These objects essentially encapsulated a pointer to the data source or data sink. This mechanism is not possible in Java because in Java pointers to data are not explicitly allowed.

The Java version of the framework introduces the concepts of data sink and data source. A a data sink is an object with a fixed number of inputs that participates in a data flow. Data sinks offer read-write access to their inputs. The inputs are always assumed to be of type 'double'. Data sinks are characterized by implementation of interface DataSink.

Similarly, a data source is an object with a fixed number of outputs that partipates in a data flow. Data sources offer read-only access to their outputs. The outputs are
always assumed to be of type 'double'. Data sinks are characterized by implementation of interface DataSource.

Data flow components see each other as instances of type DataSink and DataSource and, as far as the flow of cyclical data is concerned, are linked to each other through these two interfaces.

Back To Top, Back to Real-Time Java Project Home


Monitorable Properties

The C++ framework has the concept of property to designate an attribute of an object that is accessible in read-only mode to external objects. Properties are encapsulated in objects of type Property. This class acts as a wrapper for a pointer to the attribute underlying the property. This implementation cannot be transferred to Java because Java does not have explicit pointers to variables.

In the Java version of the framework, interface Monitorable is introduced to characterize monitorable objects. A monitorable object is an object that exposes properties that can be subjected to direct monitoring. It is therefore equivalent to a source of properties in the C++ version of the framework.

In the C++ version of the framework, some objects allow their properties to be subjected to monitoring according to the "monitoring through change notification" design pattern. This involves the monitor registering its interest in a certain property and specifying the type of change profile in which it is interested. The change profile is specified as an object of type ChangeObject. A violation of the change profile on the part of the monitored variable results in a change event being fired and in the propertyChange method of the monitoring object being invoked.

In JavaBeans application, the type of call-back action behind the monitoring through change notification design pattern should ideally be implemented using the event mechanism. Unfortunately, no satisfactory way was found to implement this design pattern using the Java event mechanism. Hence, the Java version of the framework replicates the implementation of the C++ version of the framework. The only properties upon which monitoring through change notification can be performed by default are the mode property exposed by mode managers and the manoeuvre state exposed by manoeuvre objects. In the C++ version of the framework, the reconfiguration status was exposed by configuration managers as a monitorable property. This is no longer the case in the Java version.

Monitoring through change notification in the Java version of the framework should be used only where absolutely necessary because its implementation deviates from the JavaBeans model.

Back To Top, Back to Real-Time Java Project Home


Documentation Approach

The objective is to reuse as far as possible the documentation produced for the C++ version of the framework (available from the AOCS Framework Project web site). Additional documentation that is specific to the Java-version of the framework is provided entirely through this web site.

The documents describing the C++ version of the framework are:
 

N.
Document Type
Document Description
1 AocsDescription Description of the framework domain
2 AocsArchitecture Description of the framework at framework concept level
3 <framelet name>Framelet Description of framelets at concept and architectural level (one document for each framelet)
4 AocsPrototypeDefinition Description of the AOCS prototype used to test the framework prototype
5 FrameworkPrototypeDefinition Description of the framework prototype (as opposed to the full framework defined in the design documentation)
6 TestReport Description of the tests performed to verify the framework implementation
7 ImplementationNotes Description of some framework implementation aspects
8 ImplementationCases Description of implementation cases used during the framework design phase 
9 Methodology Description of the framework design methodology 

The applicability status of these documents to the Java version of the framework is as follows:

Document 1 is applicable to both the C++ and Java versions of the framework since both are targeted at the same application domain.

Document 2 remains largely applicable. A section "Applicability to Java Version of the Framework" was added to identify parts that are specific to the C++ version of the framework.

Documents 3 remain partly applicable. The concept-level description of the framelets is the same for both the C++ and Java versions of the framework. In particular, both versions of the framework use the same design patterns. The architectural descriptions of the framelets however are only applicable to the C++ version of the framework. In the Java version of the framework, the architectural-level description is generated automatically by the JavaDoc tool. The Java source code is commented in accordance with the JavaDoc conventions and gives descriptions of all the class interfaces. Additonally, package overview documents in html are also provided and integrated in the custormary manner in the JavaDoc documentation.

Documents 4 to 6 cover the instantiation and testing of the framework and are superceded by the pages on this web site that document: the framework testing approach, the framework instantiation approach, and the prototype application instatiation.

Document 7 is specific to the C++ version of the framework and is not applicable to the Java version.

Document 8 was obsolete even with respect to the C++ version of the framework as it was not maintained through the project life. No update for the Java version is provided. Examples of implementation cases for the AOCS Framework can be found in the book "Software Frameworks and Embedded Control Systems" by A. Pasetti to be published in Dec. 2001 in the LNCS serie of Springer-Verlag.

Document 9 is superceded by the book "Software Frameworks and Embedded Control Systems" by A. Pasetti published as vol. 2231 in the LNCS series of Springer-Verlag.

Back To Top, Back to Real-Time Java Project Home


Last updated on May. 7-th 2002 by Alessandro Pasetti