4.3 AADL Model Traversal Support
OSATE has a library of traversal methods that can be effective in processing both declarative AADL models and AADL instance models. Those methods traverse the containment hierarchy of both models with appropriate filters and invoke user-defined processing methods. The processing methods can perform analysis on the content of AADL models, record results of the analysis temporarily and persistently with the models, and generate textual as well as object representations that are derived from an AADL model. The next section discusses methods and approaches for modifying the AADL models themselves.
Traversal support is located the package edu.cmu.sei.aadl.model.util.
4.3.1 Basic Traversal Support for AADL Model Processing
Basic traversal support is provided by the class ForAllAObject and its methods. This class has been designed to be tailorable for various processing needs and is used as the basis of two other traversal and processing classes discussed below.
This class has a set of traversal methods and three methods that determine the kind of processing performed on each of the visited model objects. The traversal methods are invoked in an instance of the ForAllAObject class with an AADL model object as parameter.
The class also provides methods for registering a MarkerReporter and for reporting errors, warnings, and information as persistent AADL-specific Eclipse Markers with the AADL model. For details regarding the MarkerReporter and other techniques for recording and reporting results from processing an AADL model see Section 7 Managing the Results of an OSATE Plug-in.
The intent is that a new instance of the class, or more specifically, of a specific subclass, will be created for each traversal. That is, it is not generally intended that instances of the class be reused for multiple traversals.
Default Processing of Visited Model Objects
The traversal methods visit objects of AADL models and invoke the process method on each object with the object as parameter. The default implementation of this process method invokes the suchThat method, and if that method returns true invokes the action method. The default implementation of suchThat returns true and the default implementation of action adds the visited object to a result list that is then returned as result of the traversal method. In other words, the default implementation of these three processing methods together with any of the traversal methods returns the list of visited AADL model objects.
For example, the traversal method that visits all objects in the containment hierarchy of the AADL instance model in prefix order will return a list of all instance model objects in prefix order.
Filtered Processing of Visited Model Objects
Filtered processing of visited model objects is achieved by redefining the suchThat method to a condition that must be satisfied in order for the action method to be invoked on the visited object. This method can be redefined as part of declaring an instance of the ForAllAObject class.
ForAllAObject filteredProcessing = new ForAllAObject() {
protected boolean suchThat(AObject obj) {
return obj instanceof ThreadType;
}
};
The filter defined in this example will cause a traversal method that visits all model objects to return a list of all ThreadType objects in the declarative AADL model.
Filters can check for any condition of the model object. For example, a filter can check for
    • the direction of a port
-- visit all ports with direction in
return (obj instanceof Port) &&
(((Port) obj).getDirection() == PortDirection.IN_LITERAL);
    • the name of a subcomponent
-- visit all subcomponents with the name "Peter"
return (obj instanceof Subcomponent) &&
((NamedElement) obj).getName().equals("Peter");
    • the value of a specific AADL property
-- visit all thread instances with a period of 50 ms
return (obj instanceof ComponentInstance) &&
((ComponentInstance) obj).getCategory() ==
ComponentCategory.THREAD_LITERAL) &&
(TimingUtil.getPeriod(
(ComponentInstance) obj,
PredeclaredProperties.MILLISEC) == 50);
For a number of common filtering conditions we have pre-defined specialized traversal methods (see Section 4.3.2 Traversal Methods below).
User-Defined Processing Action for AADL Model Objects
User-defined processing of visited model objects—filtered by the suchThat method—is achieved by redefining the action method. This method can be redefined as part of declaring an instance of the ForAllAObject class.
ForAllAObject userProcessing = new ForAllAObject() {
protected void action(AObject obj) {
if (obj instanceof NamedElement)
System.out.println(((NamedElement) obj).getName());
}
};
The action defined in this example will cause a traversal method that visits all model objects to print out the name of any AADL model object that has a name.
User-defined processing can be combined with a user-defined filter. The example above can be also specified as follows:
ForAllAObject userProcessing = new ForAllAObject() {
protected boolean suchThat(AObject obj) {
return obj instanceof NamedElement;
}
protected void action(AObject obj) {
System.out.println(((NamedElement) obj).getName());
}
};
Note that by redefining the action method we are replacing the collection of the visited objects in a result list by the specified action. If it is still desirable to return the visited objects in addition to taking the specified action a call to the process method of the super class, i.e., super.action(obj);
Redefined Processing Method for AADL Model Objects
User-defined processing of visited model objects is achieved by redefining the process method. This method can be redefined as part of declaring an instance of the ForAllAObject class.
ForAllAObject userProcessing = new ForAllAObject() {
protected void process(AObject obj) {
if (obj instanceof NamedElement)
System.out.println(((NamedElement)obj).getName());
}
};
The action defined in this example will achieve the same as the example in the previous section.
Redefinition of the process method is used by the AadlProcessingSwitch class to introduce a set of processing methods, one for each of the classes in the AADL meta model.
List-Based Processing Methods
The default processing methods of the traversal methods return lists of AADL model objects as a Java collection, specifically, as EList objects. EList provides a List implementation with the additional capability of acting as notifiers (see EMF book for more detail).
We have provided two capabilities for processing of such lists of AObjects:
    • QuickSort for sorting ELists of AObjects
    • processEList for processing ELists of AObjects with the same tailorable filtering and action methods that are part of the traversal support.
QuickSort
QuickSort is defined as a class with a compare method use to perform quick sorting of ELists. The default implementation of the compare method compares the string representation of two objects as made available by the toString method of the object’s class.
The default QuickSort implementation can be tailored to use a user-defined sorting criterion by defining a subclass of QuickSort with a new compare method. This can be done through an explicit class declaration or implicitly as part of an instance declaration of QuickSort. An example of the latter approach is shown in the example below, which is used in the Priority Inversion plug-in.
The example defines the sort criterion to be based on the Period property of component instances. In this particular case we assume that only lists of AObjects that are threads with a Period property are being sorted.
QuickSort quick = new QuickSort() {
protected int compare(Object obj1, Object obj2) {
double a = TimingUtil.getPeriodInUS((ComponentInstance) obj1);
double b = TimingUtil.getPeriodInUS((ComponentInstance) obj2);
if (a > b) return 1;
if (a == b) return 0;
return -1;
}
};
A list of AObjects is sorted by call to the QuickSort method on an instance of the QuickSort class.
quick.quickSort(threadList);
processEList
An EList of AObjects, whether generated by the default implementation of a traversal method, sorted by QuickSort, or constructed programmatically by the plug-in, can be further processed by the processEList method. This method is defined as a method of the ForAllAObject class and applies the process method to each element in the list, in other words, the suchThat method is applied and if it returns true the action method is applied.
As do the traversal methods, this method returns a result list. The default implementation of suchThat and action this results in the return the original list. With a redefined suchThat method the returned list consists of those list elements that satisfy the suchThat condition.
Redefinition of the action method or the process method permit further tailoring of the processEList method. The effect of their redefinition has been discussed in the previous two sections.
4.3.2 Traversal Methods
We have defined traversal methods that work on both declarative AADL models and AADL instance models as well as traversal methods specifically tailored to processing declarative model and tailored to processing instance models. The traversal methods traverse the containment hierarchy of a declarative AADL model or of an AADL instance model. The content of a model object is determined by a call to the getChildren method. The default implementation of the getChildren method for AObject objects returns the results of eContents(), i.e., all contained objects. For ComponentInstance objects this method has been redefined to support mode-specific retrieval of content. For more on mode-specific AADL instance model processing see Section Instance Model Processing.
Traversal methods that operate on AADL instance models can visit all instance model objects or only those instance model objects that are part of a given system operation mode. They do so transparent to the suchThat, action, and process methods. This allows users to develop AADL model processing plug-ins such as a scheduling analyzer that can be applied to a whole system instance as well as to each system operation mode specific configuration of the system instance without changes. Methods for setting a specific system operation mode are described in Section Modal System Instances.
Prefix and Postfix Order Traversal of Declarative and Instance Models
The following methods can be applied to both declarative AADL models and AADL instance models. Furthermore, they can be applied to the root object of an AADL model or to any other object of the AADL model. In the latter case the appropriate subset of the model is traversed.
The traversal follows the containment hierarchy of the declarative or instance model. In case of the AADL instance model the containment hierarchy corresponds to the system hierarchy. In case of the declarative AADL model the containment hierarchy does not reflect the system hierarchy nor a declaration/use hierarchy. Instead it represents the abstract syntax structure of an AADL specification.
    • processPreOrderAll(AObject start): Traverses the containment hierarchy starting with the model object start and does so in prefix order. This means that the first child of an object and its children are visited before the second child is visited. This traversal method allows information to be propagated down the model hierarchy.
    • processPostOrderAll(AObject start): Traverse the containment hierarchy using the model object start as starting point and does so in postfix order. This means that the children of an object are visited before the object itself. The start object is visited last. This traversal method allows information to be propagated up the model hierarchy.
Declaration–Use Order Traversal in Declarative AADL Models
The following traversal methods provide support for processing objects of the class ComponentImpl, i.e., for processing component implementation declarations in declarative AADL models. These methods operate on component implementations contained in the anonymous name space of an AADL specification, i.e., are contained directly in an AadlSpec object, and those that are contained in AADL packages, i.e., those contained in the public and private AadlSection objects of AadlPackage objects.
The purpose of two of these methods is to provide for processing of component implementation declarations according to a declaration/use ordering of component classifiers. This is the ordering relationship that a component implementation must be declared before it can be referenced in a subcomponent declaration.
    • processAllComponentImpl(AadlSpec as): Processes all component implementations in the order in which they have been declared in an AADL specification and AADL packages contained in the AADL specification.
    • processTopDownComponentImpl(AadlSpec as): Processes all component implementations in an AADL specification and AADL packages contained in the AADL specification in the definition–use order. This means that component implementations are visited before component implementation whose subcomponents reference them in their classifiers. This traversal method permits propagation of information down the system hierarchy and do so in the context of the declarative AADL model. This method is used by the MetaH generator to produce textual MetaH where component implementations are declared before they are used.
    • processBottomUpComponentImpl(AadlSpec as): Processes all component implementations in an AADL specification and AADL packages contained in the AADL specification in the inverse definition–use order. This means that component implementations are visited after component implementation whose subcomponents reference them in their classifiers. This traversal method permits propagation of information up the system hierarchy and do so in the context of the declarative AADL model.
Instance Model Traversal
The following methods provide support for traversing the component instance part of an AADL instance model. In other words, the component instance hierarchy representing the system hierarchy is traversed without visiting the feature instances, connection instances, etc. The methods can be invoked on the root object of an AADL instance model, i.e., a SystemInstance object, or on any ComponentInstance object as the root of the traversal.
    • processPreOrderComponentInstance(ComponentInstance start): Traverses the component instance hierarchy starting with the component instance object start and does so in prefix order. This means that the first child of an object and its children are visited before the second child is visited. This traversal method allows information to be propagated down the system instance hierarchy.
    • processPostOrderComponentInstance(ComponentInstance start): Traverses the containment hierarchy using the model object start as starting point and does so in postfix order. This means that the children of an object are visited before the object itself. The start object is visited last. This traversal method allows information to be propagated up the model hierarchy.
A variant of these methods has been provided that limits the traversal to a certain category of component instances. These methods can be used to, for example, traverse all processor instances, and—by using the default implementation of the action method—to return the list of processor instances.
    • processPreOrderComponentInstance(ComponentInstance start, ComponentCategory cat): Traverse the component instance hierarchy starting with the component instance object start and does so in prefix order. This means that the first child of an object and its children are visited before the second child is visited. This traversal method allows information to be propagated down the system instance hierarchy.
    • processPostOrderComponentInstance(ComponentInstance start, ComponentCategory cat): Traverse the containment hierarchy using the model object start as starting point and does so in postfix order. This means that the children of an object are visited before the object itself. The start object is visited last. This traversal method allows information to be propagated up the model hierarchy.
Traversal and Multi-File Support
OSATE supports storage of models in multiple files. Each package and each property set can be stored in a separate XML document/EMF resource/file. We have extended some of the traversal methods to not only traverse all objects in a single XML document, but in all packages, property sets, and AadlSpec files in an Eclipse workspace.
    • processPreOrderAll(): Traverses the containment hierarchy over the whole OSATE workspace and does so in prefix order.
    • processPostOrderAll(): Traverses the containment hierarchy over the whole OSATE workspace and does so in postfix order.
    • processAllComponentImpl(): Processes all component implementations in the OSATE workspace.
    • processTopDownComponentImpl(): Processes all component implementations in the OSATE workspace in the definition–use order.
    • processBottomUpComponentImpl(): Processes all component implementations in the OSATE workspace in the inverse definition–use order.
    • processPreOrderAllDeclarativeModels(): Traverses the component hierarchy of all declarative models in the OSATE workspace in prefix order.
    • processPostOrderAllDeclarativeModels (): Traverses the component instance hierarchy of all declarative models in the OSATE workspace in postfix order.
    • processPreOrderAllComponentInstances(): Traverses the component instance hierarchy of all instance models in the OSATE workspace in prefix order.
    • processPostOrderAllComponentInstances(): Traverses the component instance hierarchy of all instance models in the OSATE workspace in postfix order.
4.3.3 An Example: Priority Inversion Checking
We have included much of the implementation of a plug-in that checks for priority inversion of periodic threads assigned to the same processor, if they have manually assigned priorities.
The first method is applied to an AADL instance model by passing in a SystemInstance object as the root of the instance model. The method invokes the method checkPriorityInversion on every processor instance object. It does so by redefining the process method and by invoking the component instance traversal method for the component category of processor on the system instance as the root of the traversal.
An alternate implementation of this method
public void checkSystemPriorityInversion(SystemInstance si) {
ForAllAObject mal = new ForAllAObject() {
public void process(AObject obj) {
checkPriorityInversion((ComponentInstance) obj);
}
};
mal.processPreOrderComponentInstance(si,
ComponentCategory.PROCESSOR_LITERAL);
}
An alternate implementation of this method uses the default implementation of ForAllAObject to generate the processor list and then iterates over it to perform the checking on each processor. It utilizes a predeclared instance of the default implementation of ForAllAObject.
public void checkSystemPriorityInversion(SystemInstance si) {
EList proclist =
ForAllAObject.INSTANCE.processPreOrderComponentInstance(
si, ComponentCategory.PROCESSOR_LITERAL);
for (Iterator it = proclist.iterator(); it.hasNext();) {
checkPriorityInversion((ComponentInstance) it.next());
}
}
The second method generates a list of all threads that are bound to a specific processor, sorts the thread list with QuickSort according to their period (see Section 4.3.1.5.1 QuickSort above), and then checks the sorted list for increasing monotonicity of the priority across thread rate groups by calling on the method checkIncreasingMonotonicity. The threadlist is created by redefining suchThat to compare the value of the actual processor binding property of a thread to the current processor of the inversion analysis and invoking the component instance traversal for the category of thread.
/**
* check for priority inversion of thread bound to the given processor
* @param curProcessor ComponentInstance of processor
*/
public void checkPriorityInversion(ComponentInstance curProcessor) {
SystemInstance root = curProcessor.getSystemInstance();
// final makes currentProcessor accessible to the refined suchThat
final ComponentInstance currentProcessor = curProcessor;
EList boundThreads = new ForAllAObject() {
protected boolean suchThat(AObject obj) {
ComponentInstance boundProcessor =
TimingUtil.getActualProcessorBinding((ComponentInstance)obj);
return (boundProcessor == currentProcessor);
}
}.processPreOrderComponentInstance(
root, ComponentCategory.THREAD_LITERAL);
/* We will sort the thread list by period and check to make sure
* the assigned priority is monotonically decreasing.
*/
periodSort.quickSort(boundThreads);
checkIncreasingMonotonicity(boundThreads);
}
4.3.4 Meta-Model Class Based AADL Model Processing
There are situation where processing an AADL model requires different actions for different AADL model objects. For example, semantic checking is different for different model objects, and the textual AADL generator has produces different text for different objects of the declarative AADL model.
In support of model object specific processing the Eclipse Modeling Framework (EMF) generates a meta model specific switches for each of the meta model packages. Each switch consists of a collection of case methods, one for each class defined in the meta model package. We refer to these methods as case methods because they are named caseClassName.
A switch processing method invoked with an AADL model object identifies the appropriate case method. The default implementation of each case method has no action and returns the value NOT_DONE (null). Given this return value the switch processing method also invokes the case method of each super class in turn until a case method returns DONE (non-null value) or the case method of the common super class has completed. This permits processing to be specified for each of the model object classes, while at the same time allows processing that is common to a number of classes to be specified once in a common super class.
The class AadlProcessingSwitch utilizes these meta model package specific switches to provide meta model class based processing of AADL models. This class is defined as a subclass of the ForAllAObject class and as a result provides this meta model class specific processing in the context of the model traversal methods defined as part of ForAllAObject. This is accomplished by redefining the process method to invoke the appropriate switch processing method instead of creating a result list of visited objects.
This class and its methods have been used to implement much of the AADL front-end processor, including the name resolver, semantic checker, property value checker, and numeric resolver. It has also been used in the implementation of a number of OSATE plug-ins, such as the textual AADL generator, the MetaH generator, the flow latency analyzer, and the model statistics plug-in. In some cases the switch processing capability is used in conjunction with the traversal methods, while in other cases the switch processing capability is used without the traversal methods.
Traversal-Driven Switch Processing
Traversal-driven switch processing involves two steps:
    • The specification of meta model class specific processing actions by redefining the appropriate case methods in the meta model package specific switches
    • The selection of the appropriate traversal method to visit the correct set of model object for which the switch-based processing method will be automatically invoked.
The model statistics plug-in is a prime example for the use of traversal-driven switch processing since this plug-in intends to keep track of the number of occurrences of different AADL model objects. We will use code fragments from it as examples in this section.
Redefinition of Case Methods
The case methods are redefined by subclassing the class AadlProcessingSwitch and by introducing new case method declarations as part of a meta model package specific switch instance declaration in the constructor method of the AadlProcessingSwitch subclass. In our example below we define the subclass ModelStatistics with two counter instance variables. The constructor calls the super class and then redefines the case methods for two classes in the flow package of the AADL meta model. This is done as part of the instance declaration of the flow switch. Its assignment to flowSwitch registers the redefined switch with the AadlProcessingSwitch mechanism.
The first redefined case method is that of the abstract class FlowSpec that is the super class of several concrete classes (FlowPathSpec, FlowSourceSpec, FlowSinkSpec—see the AADL meta model in Annex D). The effect is that all flow specification declarations are counted in a single count. The return value DONE indicates that the case method for its super class will not be called.
The second redefined case method is that of the concrete class EndToEndFlow. This class represents end-to-end flow declarations in the declarative AADL model. In this case end-to- end flow declarations are counted by themselves. The return value DONE indicates that the case method for its super class will not be called.
public class ModelStatistics extends AadlProcessingSwitch {
private int flowcount = 0;
private int endtoendflowcount = 0;

public ModelStatistics() {
super(); // required call to initialize the super class
flowSwitch = new FlowSwitch() {
public Object caseFlowSpec(FlowSpec obj) {
flowcount++;
return DONE;
}
public Object caseEndToEndFlow(EndToEndFlow obj) {
endtoendflowcount++;
return DONE;
}
};
// other switch redefinitions
} // end constructor
} // end class
The textual AADL generator (called Unparser in the OSATE implementation) makes use of case method processing of a class and its super class. For example, the case method for an object of class ThreadType contributes the reserved word thread and returns NOT_DONE, while the case method of its super class ComponentType generates the rest of the AADL text, which is common to all component types.
Note, however, that the call to the super class case method does not return to the subclass case method. This means super class case methods can only add to any processing performed by a case method, i.e., processing of the two cannot be interleaved. The section Content-Driven Switch Processing shows how interleaved processing can be achieved.
Invocation of the Processing Switch
The model statistics processing switch is called by a method that makes this capability available as a command action in the AADL Object Editor (see AADL Object Editor Command Actions). From the currently selected model object we retrieve the AadlSpec object via the getAadlSpec method. This method returns the AadlSpec object for both an object selected in the AADL instance model and an object selected in a declarative AADL model. Similarly, we retrieve the system instance by calling the getSystemInstance method. This method returns null if called on a declarative AADL model and the SystemInstance object if called on an AADL instance model. We then call the statistics processing switch through the traversal method processPreOrderAll on the AadlSpec object, and on the SystemInstance object if it is non-null.
// obj is the currently selected object
AadlSpec as = obj.getAadlSpec();
SystemInstance si = obj.getSystemInstance();
ModelStatistics stats = new ModelStatistics();
stats.processPreOrderAll(as);
if (si != null) {
stats.processPreOrderAll(si);
}
Content-Driven Switch Processing
Traversal-driven switch processing with case method invocation according to the meta model class hierarchy is not always appropriate. In this section we examine several situations where more control over the order in which processing is to be performed is required.
Controlling the Invocation of the Super Class Case Method
There are also situations where we need to perform processing based on a specific class as well as its super class and do so such that the processed information from the class and its super class are interleaved. This can be achieved in one of two ways:
    • All processing is performed by the case method of the model object class without utilizing the case method of the super class. All relevant information about the model object is accessible to the processing action. This approach provides full control over what information is processed when, but may lead to unnecessary replication of common code in several case methods.
    • The case method of a class explicitly invokes the case method of its super class. This provides control over when information in the super class is processed. However, it limits super class processing to a single set of actions. In other words, if different super class processing actions are desired by multiple calls to the super class from the same subclass a global processing mode variable may have to be used to achieve conditional processing in the super class case method.
Controlling the Processing Order
There are situations where model object must be processed in an order different from the traversal order. A case in point is the MetaH generator, where we must generate the port data types as port type declarations, and then generate the component type and implementation declarations in declaration use order.
This can be achieved by not including certain model object classes in the set of model object visited by the traversal method and by invoking the switch processing method of those model objects explicitly in the case method of a model object class. This is accomplished by a process method call on the AadlProcessingSwitch itself with the target model object as parameter. In the example below, we retrieve the list of features of a thread subcomponent. These are actually retrieved from the component type referenced by the subcomponent classifier according to the type inheritance of the AADL meta model by calling on the getAllFeature method.
EList featurelist = threadsubcomp.getAllFeature();
for (Iterator it = featurelist.iterator();it.hasNext();) {
self.process((Feature) it.next());
}
The instance of the AadlProcessingSwitch or its subclass is accessible to the case methods through the instance variable self in the switch instance, which is initialized by the AadlProcessingSwitch constructor—the reason for the super() call in the ModelStatistics constructor in the previous section.
Processing of Referenced Model Objects
There are situations where information must be processed from model objects that are referenced by a model object rather than being contained in a model object. For example, the textual AADL generator must add into the output of a subcomponent the name of the classifier object referenced by the subcomponent object.
There are several options of accomplishing this:
    • The subcomponent case method retrieves the name of the referenced classifier object and generates the appropriate output.
    • The subcomponent case method calls the switch processing method on the referenced model object.
    • A ContentProvider adapter factory is used to determine the children of a model object to be used by the traversal methods.
The first option has been discussed in the first bullet of Section 4.3.4.2.1 Controlling the Invocation of the Super Class Case Method above. The second option has been discussed in Section 4.3.4.2.2 Controlling the Processing Order above.
A simple form of the third option has been used to accommodate processing of modal instance models by providing system operation mode specific traversal. This is achieved through a ModalInstanceAdapter. This adapter is utilized by the getChildren method for ComponentInstance objects to determine the mode-specific subset of the children. For details on mode-specific processing of AADL instance models the reader is referred to Section Instance Model Processing.
A more sophisticated form of the third option involves utilizing and redefining a set of content provider adapters and content provider adapter factories for the AADL meta model packages that has been generated by EMF for the AADL Object Editor. They can be found in the OSATE Eclipse project edu.cmu.sei.aadl.model.edit in the Java packages edu.cmu.sei.aadl.model.metamodelpackage.provider. The CoreEditor class in the Java package edu.cmu.sei.aadl.model.core.presentation uses and redefines these content provider adapter factories to an Instance content provider for declarative AADL models without generation of an AADL instance model by offering as content of a subcomponent the subcomponents of its classifier.
In summary, the third option localizes the definition of constitutes the children for the purpose of traversal to a collection of meta model class specific adapters.