![]() ![]() |
||||
|
||||
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. |
||||
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. |
||||
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 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
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 of visited model objectsfiltered by the suchThat methodis
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); |
||||
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. |
||||
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
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 objects 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); |
||||
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. |
||||
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. |
||||
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.
|
||||
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.
|
||||
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.
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, andby using the default implementation of the action methodto return the
list of
processor instances.
|
||||
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.
|
||||
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);
} |
||||
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 involves two steps:
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. |
||||
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, FlowSinkSpecsee 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. |
||||
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);
} |
||||
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. |
||||
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:
|
||||
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 constructorthe reason for the super() call in the ModelStatistics
constructor in the previous section. |
||||
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
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. |
||||