9/14/2006
1
OSATE Plug-in Development Guide
Peter H. Feiler ([email protected]) Aaron Greenhouse ([email protected])
Software Engineering Institute Carnegie Mellon University
Pittsburgh PA 15213
August 2006
Each section is now marked with whether it is up-to-date or not.
Mostly up-to-date, but some important things have changed:
• Section 3
Needs to be rewritten:
• Section 9
9/14/2006
3
Table of Contents 1 Reader’s Notes ............................................................................................................ 7
1.1 Assumptions About Audience ............................................................................ 7
1.2 More Stuff Here .................................................................................................. 7
2 Setting Up OSATE ..................................................................................................... 9
2.1 Getting the Eclipse/OSATE Components........................................................... 9
2.2 Installing Eclipse/OSATE................................................................................. 10
2.2.1 Installing the OSATE SDK Archive......................................................... 11
2.2.2 Adding the Plug-ins Using Eclipse Update Sites...................................... 11
2.2.3 Installing Eclipse and the Plug-ins Separately.......................................... 11
2.2.4 Uninstalling Eclipse/OSATE.................................................................... 12
2.3 Verify the Installation ....................................................................................... 12
3 A First Plug-in: Model Statistics............................................................................... 13
3.1 Writing the Analysis Code................................................................................ 13
3.1.1 Creating an OSATE Plug-in Project ......................................................... 13
3.1.2 Setting the Plug-in’s Dependencies .......................................................... 15
3.2 Gathering Model Statistics................................................................................ 17
3.2.1 Subclassing AadlProcessingSwitch .......................................................... 17
3.2.2 The ModelStatistics Code ......................................................................... 19
3.2.3 An Alternative Use of Switches................................................................ 23
3.3 Driving the Plug-in ........................................................................................... 24
3.3.1 Eclipse Actions ......................................................................................... 25
3.3.2 The Model Statistics Action Code ............................................................ 26
3.4 Creating an Icon for the Plug-in........................................................................ 28
3.5 Describing the Action in the plugin.xml File.................................................... 29
3.5.1 The Complete plugin.xml File .................................................................. 31
3.6 Executing the Model Statistics Plug-in............................................................. 33
3.6.1 Model Statistics in Action......................................................................... 36
3.7 Deploying Model Statistics............................................................................... 39
3.8 Summary of Concepts....................................................................................... 41
3.8.1 Eclipse....................................................................................................... 42
3.8.2 Meta Model............................................................................................... 42
3.8.3 OSATE API .............................................................................................. 43
4 Processing of AADL Models.................................................................................... 45
4.1 Meta Model Defined AADL Models................................................................ 45
4.2 Notes on Accessing Models.............................................................................. 47
4.2.1 An API for Accessing AADL Models ...................................................... 47
4.2.2 Eliding Model Structure............................................................................ 48
4.2.3 AADL Inheritance Semantics ................................................................... 49
4.2.4 Specialized Reference Associations ......................................................... 50
4.2.5 Unifying “Either-Or” Associations........................................................... 51
4.2.6 Specific Instances of the Getter Method Patterns ..................................... 52
4.3 AADL Model Traversal Support ...................................................................... 54
4.3.1 Basic Traversal Support for AADL Model Processing ............................ 55
4.3.2 Traversal Methods .................................................................................... 59
9/14/2006
4
4.3.3 An Example: Priority Inversion Checking................................................ 63
4.3.4 Meta-Model Class Based AADL Model Processing ................................ 64
4.3.5 Reporting Markers During a Traversal ..................................................... 69
4.4 AADL Model Manipulation Support................................................................ 70
5 Processing AADL Properties.................................................................................... 73
5.1 The Security Level Plug-in ............................................................................... 73
5.2 An Overview of AADL Properties ................................................................... 73
5.2.1 AADL Property Types.............................................................................. 74
5.2.2 AADL Property Declarations ................................................................... 77
5.2.3 Basic AADL Property Associations ......................................................... 79
5.2.4 The “SecurityLevel” Property................................................................... 80
5.2.5 Property Lookup ....................................................................................... 81
5.3 AADL Properties in the Meta Model................................................................ 83
5.3.1 Properties and the Instance Model ............................................................ 86
5.4 Implementing the Security Level Plug-in ......................................................... 87
5.4.1 Getting the Property Declaration and Driving the Analysis ..................... 88
5.4.2 Class ComponentSecuritySwitch.............................................................. 90
5.4.3 Class ConnectionSecuritySwitch .............................................................. 92
5.5 Getting Simple Property Values ....................................................................... 93
5.6 Manipulating Property Values .......................................................................... 95
5.6.1 Copying PropertyValues........................................................................... 95
5.6.2 Unparsing Property Values ....................................................................... 96
5.6.3 Using Range Values.................................................................................. 96
5.6.4 Getting Type Literals ................................................................................ 96
5.6.5 Scaling Number Values ............................................................................ 97
5.6.6 Setting Number Values ............................................................................. 97
5.7 Advanced Property Associations ...................................................................... 98
5.7.1 Modal Property Associations.................................................................... 99
5.7.2 Nonexistent Property Values .................................................................. 100
5.7.3 Modes and Property References ............................................................. 100
5.8 OSATE Properties API ................................................................................... 101
5.8.1 Using Predeclared Properties.................................................................. 101
5.8.2 More about AaxlReadOnlyAction.initPropertyReferences .................... 102
5.8.3 General Lookup of Property Sets, Definitions, Constants, and Types ... 103
5.8.4 Testing “Applies to” ............................................................................... 105
5.8.5 Getting Property Values.......................................................................... 105
5.8.6 Modifying Property Associations ........................................................... 109
6 Working with Flows ............................................................................................... 113
6.1 Flow Specifications and Flow Instances......................................................... 113
6.1.1 Flow Specification Declarations ............................................................. 114
6.1.2 Flow Implementation Declarations......................................................... 114
6.1.3 End-To-End Flow Declarations .............................................................. 116
6.1.4 End-To-End Flow Instances ................................................................... 116
6.1.5 Textual Flow Declaration Examples....................................................... 118
6.2 Flows in the AADL Meta Model .................................................................... 119
6.2.1 Flow Specification Declarations ............................................................. 119
9/14/2006
5
6.2.2 Flow Implementations and End-To-End-Flows...................................... 120
6.2.3 End-To-End Instance Flows ................................................................... 122
6.3 The Flow Analysis Plug-in ............................................................................. 122
6.3.1 Meeting Flow Requirements................................................................... 123
6.3.2 Handling of Missing Latency Properties ................................................ 125
6.3.3 Propagation of Flow Latency Information.............................................. 126
6.3.4 Reusing the Analysis for Instance Models.............................................. 127
6.4 Specification-Based End-To-End Flow Analysis ........................................... 128
6.4.1 The Display System Model Scenario...................................................... 128
6.4.2 The Partition Latency Analysis............................................................... 130
6.4.3 Partition Latency Analysis Refinement .................................................. 131
6.5 Latency Analysis with Instance Models ......................................................... 133
7 Writing Eclipse/OSATE Actions............................................................................ 135
8 Managing the Results of an OSATE Plug-in .......................................................... 137
8.1 Comparison of Result Management Mechanisms .......................................... 137
8.1.1 Use of Eclipse Markers........................................................................... 137
8.1.2 Use of SWT Dialog box.......................................................................... 137
8.1.3 Use of AADL Properties......................................................................... 137
8.1.4 Use of Adapters on AADL Models ........................................................ 138
8.1.5 Use of the File System ............................................................................ 138
8.1.6 Use of Meta Model-Based XML Documents ......................................... 138
9 Persistent Markers with AADL Models ................................................................. 139
9.1 OSATE Marker Types .................................................................................... 141
9.1.1 Defining New Marker Types .................................................................. 141
9.2 Managing Markers with MarkerReporter ....................................................... 143
9.2.1 Reporting Markers .................................................................................. 144
9.2.2 Creating MarkerReporter Objects........................................................... 145
9.2.3 Limiting the Number of Markers ............................................................ 146
9.2.4 Deleting Markers .................................................................................... 147
9.3 Reporting Errors in the Plug-in....................................................................... 147
10 Packages Provided by the OSATE Plug-ins ....................................................... 149
9/14/2006
7
1 Reader’s Notes • Purpose
• Goals
• Sections
• Etc.
For OSATE release 1.0.0
1.1 Assumptions About Audience
We assume that the reader is familiar with using the Eclipse IDE. At a minimum we
assume that the reader has built Java projects in Eclipse, and is generally comfortable
with using the IDE.
This document is not a tutorial on the AADL meta model, although we discuss relevant
meta-model issues as needed. We refer the reader to the AADL Meta Model and
Interchange Formats annex for the complete meta model specification. However, there
are additional methods on the meta model classes that are not part of the meta model
proper. These methods are introduced and discussed in this document.
Furthermore, the AADL meta model is implemented using the Eclipse Modeling
Framework (EMF). We do not assume that the reader is familiar with this framework. We
introduce relevant concepts as needed, although this document is not intended to be an
introduction to EMF. For more advanced usage, the reader is referred to [EMF Reference
Here].
We do not assume that the reader has set up an Eclipse environment for building OSATE
Plug-ins. Section 2 “Setting Up OSATE” describes how to do this.
1.2 More Stuff Here
More assumptions and clarifications go here. What are assuming about Eclipse plug-in
knowledge?
9/14/2006
9
2 Setting Up OSATE This section is basically true, but the details about the particular versions are probably wrong.
This section describes how to set up your Eclipse environment so that you can run
OSATE and develop plug-ins to OSATE. You need to have a Java SDK installed, at least
version 1.4.2. This guide does not cover the installation of the JVM and Java SDK. For
OSATE, you need to install four components:
1. The Eclipse IDE.
2. The Eclipse Modeling Framework (EMF) plug-ins.
3. The OSATE frontend plug-ins.
4. The OSATE analysis plug-ins (optional).
If you already have Eclipse (at least version 3.0.2) installed, you can install the EMF and
OSATE plug-ins into it, or you can create a new Eclipse/OSATE installation. Plug-ins
can be installed into an existing Eclipse using “update sites,” or by downloading and
unzipping the plug-ins directly. You can also install a separate copy of Eclipse/OSATE
if you do not wish to alter your existing Eclipse installation.
If you do not already have Eclipse installed, the simplest way to proceed to is to
download a complete Eclipse/OSATE SDK that is packaged with all the necessary plug-
ins from the AADL homepage.
The OSATE analysis plug-ins are not needed to develop plug-ins to OSATE, but they
populate the OSATE environment with useful analyses.
2.1 Getting the Eclipse/OSATE Components
If you do not already have Eclipse installed, it is easiest to download the single OSATE
SDK distribution:
• Download the OSATE SDK from the AADL homepage,
http://www.aadl.info/. The current version, dated 31 May 2005, bundles
together Eclipse 3.0.2, EMF 2.0.2, and OSATE 1.0. There are distributions for
Windows, Linux, and MacOS X. The base filename is osate-1.0-sdk-
eclipse-3.0.2-emf-2.0.2-05312005 with the extention -win32.zip, -linux-
gtk.zip, or -macosx-carbon.tar.gz.
If you already have Eclipse installed, and you want to install the plug-ins from their
“update sites,” you should configure Eclipse to use the following sites:
9/14/2006
10
• The EMF/SDO/XSD SDK can be retrieved from the update site
http://download.eclipse.org/tools/emf/updates/site-release.xml.
You need at least version 2.0. As of this writing, the preferred version is release
2.0.2.
• The OSATE frontend and OSATE analysis plug-ins can be retrieved from the
update site http://la.sei.cmu.edu/aadlinfosite/OSATEUpdateSite. The
current version of both is 1.0.
If you are installing all the components piecemeal, you need to download the following
distributions:
• Download the Eclipse SDK—not the Runtime—from the Eclipse homepage,
http://www.eclipse.org/. You need at least version 3.0. As of this writing,
the preferred version is release 3.0.2. The filename of the distribution is
eclipse-SDK-3.0.2-XXX.zip, where XXX is the name of the platform, e.g.,
win32 or linux-gtk.
• Download the EMF/SDO/XSD Software Development Kit (SDK) from the EMF
homepage, http://www.eclipse.org/emf/. You need at least version 2.0. As
of this writing, the preferred version is release 2.0.2. The filename should be
emf-sdo-xsd-SDK-2.0.2.zip.
• Download the OSATE frontend from the AADL homepage,
http://www.aadl.info/. As of this writing, the current version is 1.0. The
filename should be osate-frontend-1.0-05312005.zip.
• (Optional.) Download the OSATE analysis plug-ins from the AADL homepage,
http://www.aadl.info/. The current version is 1.0. The filename should be
osate-plugins-1.0-05312005.zip.
2.2 Installing Eclipse/OSATE
You can have more than one installation of Eclipse on your system, each with it its own
set of plug-ins. The Eclipse archive (and the all-in-one OSATE archive) unzips into a
single folder named eclipse. Each Eclipse “installation” is independent of any other
Eclipse installation folder on your system, and you can even have several different
versions of Eclipse installed. Thus, if you already have Eclipse installed, you can either
install OSATE on top of that installation, by just unzipping the EMF and OSATE
archives into it, or you can create a separate OSATE installation.
9/14/2006
11
2.2.1 Installing the OSATE SDK Archive
To install the OSATE SDK from a single distribution, simply unzip the archive to your
preferred application directory. The archive unzips into a directory named eclipse, so,
for example, if you unzip to C:\Program Files, you will end up with the directory
C:\Program Files\eclipse.
You can rename the eclipse directory if you like. For example, you might like to add
the version of the Eclipse distribution to the name, or mark that it contains the OSATE
plug-ins, e.g., eclipse-3.0.2-OSATE-SDK-1.0.
2.2.2 Adding the Plug-ins Using Eclipse Update Sites
If you have an exising Eclipse installation to which you want to add the EMF and
OSATE plug-ins, you can have Eclipse download and install the plug-ins from their
“update sites.” This is accessed using the menu item “Help | Software Updates |
Find and Install…”. Use the update sites described above in Section 2.1 “Getting the
Eclipse/OSATE Components”.
2.2.3 Installing Eclipse and the Plug-ins Separately
To install the components piecemeal,
1. Unzip the Eclipse archive into your preferred location for applications (e.g.,
C:\Program Files). It unzips to a directory named eclipse.
2. Unzip the EMF archive into the same directory as you installed Eclipse (e.g.,
C:\Program Files). It also installs into a directory named eclipse, adding new
components to the features and plugins subdirectories.
3. Unzip the OSATE frontend archive into the Eclipse directory (e.g., C:\Program
Files\eclipse). It unzips into features and plugins directories, adding new
components to the existing subdirectories in the eclipse directory.
4. Unzip the OSATE analysis plug-ins archive into the Eclipse directory (e.g.,
C:\Program Files\eclipse). It unzips into features and plugins directories,
adding new components to the existing subdirectories in the eclipse directory.
You can now rename the eclipse directory if you like. For example, you might like to
add the version of the Eclipse distribution to the name, or mark that it contains the
OSATE plug-ins, e.g., eclipse-3.0.2-OSATE-SDK-1.0.
9/14/2006
12
2.2.4 Uninstalling Eclipse/OSATE
To remove an Eclipse installation, you can simply delete folder containing Eclipse, e.g.,
C:\Program Files\eclipse.
If you installed the EMF and OSATE plug-ins into an existing Eclipse installation, you
can selectively disable and re-enable them using the “Product Configuration” dialog box
accessed using the “Help | Software Updates | Manage Configuration…” menu
item. If you added the plug-ins using their update site, you can also uninstall them using
this dialog box.
2.3 Verify the Installation
Run Eclipse. If you installed using the single OSATE SDK archive, you will see the
splash screen shown in Figure 1. Otherwise, you will see the standard Eclipse splash
screen.
Figure 1: Eclipse/OSATE 1.0 splash screen.
To check that the needed plug-ins have been installed, go to “Help | About Eclipse
Platform.” In addition to the icon for the Eclipse features ( ) you should see an
icon for the OSATE features ( ). Click on the Eclipse icon to view the list of
Eclipse features. The list should include several EMF-related features, such as “Eclipse
Modeling Framework (EMF)”, and “EMF Service Data Objects (SDO).” Click on “Ok.”
Click on the OSATE icon to view the list of OSATE features. You should see the
OSATE frontend and the OSATE analysis plug-ins (if installed).
9/14/2006
13
3 A First Plug-in: Model Statistics A lot of details of this section need to be updated. In particular, the preferred parent class for an
action is now AaxlReadOnlyActionAsJob. Also should discuss the use of the progress monitor.
Our first OSATE plug-in computes information about an AADL model. It counts the
number of component types, component implementations, and flow specifications
declared in an AADL specification. It also counts the number of threads, processes,
semantic connections, processors, buses, memories, and devices that are instantiated in an
AADL system instance.
Although the functionality of this “Model Statistics” plug-in is quite simple, this example
demonstrates how to
• Create a new OSATE Plug-in project.
• Traverse AADL specification and instance models.
• Create a new OSATE Action class.
• Report analysis results.
This section describes the steps necessary to create a plug-in that performs the model
statistics analysis, and includes the complete Java source code and plugin.xml file
needed to implement it. The model statistics analysis, however, is available as part of the
“Architecture Checker” plug-in in the OSATE Analysis Plug-ins feature
edu.cmu.sei.osate-plugins. If you have this plug-in installed, you can examine its source
code in Eclipse by creating a new plug-in project, see below, that also depends on the
edu.cmu.sei.aadl.architecture plug-in. You can then open the source code for the
ModelStatistics class by using Eclipse’s “Navigate | Open Type…” command.
3.1 Writing the Analysis Code
The simplest way to create an OSATE plug-in is to either copy and paste one of the
example plug-in projects. Here we show how to create a new OSATE plug-in project
from scratch.
3.1.1 Creating an OSATE Plug-in Project
Create a new plug-in project using the Eclipse project wizard.
1. Select “File | New | Project...” to open the project wizard. See Figure 2.
9/14/2006
14
Figure 2: Creating a new project.
2. Select “Plug-in Project” and click on “Next.” See Figure 3.
Figure 3: Selecting the plug-in project wizard.
3. Enter a name for the plug-in. This name is also used for the Java package that will
contain the source files for this plug-in. Therefore, this name should be Java
package-style name. Here we use edu.cmu.sei.osate.examples.statistics.
9/14/2006
15
4. Click on “Next.”
5. Click on “Finish.”
A new project and source tree will be created; the structure of the newly created plug-in
package is shown in Figure 4.
Figure 4: The contents of the new plug-in project.
The wizards creates
• A new Java package with the same name as the plug-in project.
• A new class, StatisticsPlugin, that manages the lifecycle of the plug-in. In
general, you do not need to edit this class.
• An OSGi bundle manifest file, MANIFEST.MF, in the subdirectory META-INF. This
file contains information about the plug-ins dependencies on other plug-ins, and
other information about the plug-in itself.
• A build.properties file that influences how Eclipse compiles and packages the
plug-in. You generally do not need to edit this file.
3.1.2 Setting the Plug-in’s Dependencies
Our first concern is establishing the plug-in’s dependencies on other plug-ins. Plug-ins
export Java packages into the Eclipse environment and, conversely, must declare which
plug-ins they depend on. By default, a plug-in project generated from the “Plug-in
Project” wizard depends on the org.eclipse.ui and org.eclipse.core.runtime plug-ins.
Our model statistics plug-in utilizes the AADL meta-model, which is itself modeled
using the Eclipse Modeling Framework (EMF). The plug-in, therefore, must also depend
on the edu.cmu.sei.aadl.model plug-in and the org.eclipse.emf.ecore plug-in. In
9/14/2006
16
general, it is expected that any OSATE plug-in will use the AADL meta-model, and thus
depend on these two packages.
Our model statistics plug-in also depends on the plug-in edu.cmu.sei.osate.ui. This
plug-in defines abstract implementations of Eclipse actions that we extend to drive the
plug-in from Eclipse’s user interface; see Section 3.3.1 “Eclipse Actions.” See Section 1
“Packages Provided by the OSATE Plug-ins” for a description of which packages are in
which OSATE plug-ins.
Plug-in dependencies are declared in the MANIFEST.MF file:
1. Edit MANIFEST.MF. Eclipse opens a unified editor that edits the contents of
MANIFEST.MF, build.properties, and plugin.xml (a file that we will create
and edit later).
2. Go to the “Dependencies” pane. See Figure 5.
3. Click on “Add...” under “Required Plug-ins.”
4. Select the appropriate plug-in(s) to add from the list. In this case we want to add
the plug-ins edu.cmu.sei.aadl.model, org.eclipse.emf.ecore, and
edu.cmu.sei.osate.ui. See Figure 6.
Figure 5: Editing a plug-in's dependencies.
9/14/2006
17
Figure 6: Selecting a plug-in.
3.2 Gathering Model Statistics
To gather the model’s statistics, the plug-in must traverse the AADL specification or
system instance and count the occurrences of the various model elements. We create a
subclass of AadlProcessingSwitch for this purpose. Class AadlProcessingSwitch
• Provides model traversal methods (inherited from class ForAllAObject).
• Leverages the EMF “switch” class concept to allow the specification of
processing methods for each class of object in the AADL model.
To compute the model statistics, we create a new subclass, ModelStatistics, that defines
the statistics gathering functionality. But first we take a closer look at class
AadlProcessingSwitch.
3.2.1 Subclassing AadlProcessingSwitch
Class AadlProcessingSwitch, and its superclass ForAllAObject, are declared in the
OSATE package edu.cmu.sei.aadl.model.util in plug-in edu.cmu.sei.aadl.model.
Together they provide a flexible and extensible framework for implementing model
traversals.
9/14/2006
18
Abstract class ForAllAObject defines methods for traversing AADL models. The
traversals invoke the method process(AObject) to process each model element. The
default implementation of process implements functionality for filtering model elements
via the suchThat method; see Section 4.3.1 “Basic Traversal Support for AADL Model
Processing” for more information. Traversal methods include
• Top-down and bottom-up traversals on both declarative and instance models.
• Methods to process lists of model objects.
• Modal traverals based on system operation modes (see xxx).
Class AadlProcessingSwitch extends ForAllAObject. It overrides the process method
to leverage the EMF “switch” class concept (see EMF book page xxx). It effectively
delegates to a distinct processing method for each abstract and concrete class in the
AADL meta model. Specifically, for each AADL meta model package, there is an EMF
“switch” class that contains a “case” method for each class declared in the package. The
AADL meta model is described using seven EMF packages:
• core
• component
• connection
• feature
• flow
• instance
• property
Thus there are seven switch classes for AADL models. For example, the AADL
component types are modeled by classes in the EMF Ecore package component. Thus
there is a class ComponentSwitch, in package edu.cmu.sei.aadl.model.component.util,
with methods caseBusType(BusType),
caseComponentClassifier(ComponentClassifier), caseDataImpl(DataImpl), etc.
When a switch class instance is invoked on a model object using doSwitch(EObject),
control flows to the appropriate “case” method based on the class of the object. The
“switch” class respects the class hierarchy, and invokes the most specific “case” method
first, falling through to case methods for super classes as long as null is returned. The
final “case” method is defaultCase(EObject). For example, when doSwitch is passed
9/14/2006
19
an instance of SystemType, the following methods are invoked, in order, until one of
them returns a non-null value:
1. caseSystemType
2. caseComponentType
3. caseSystemClassifier
4. caseComponentClassifier
5. caseClassifier
6. casePropertyHolder
7. caseNamedElement
8. caseAObject
9. defaultCase
The default implementation of each “case” method does nothing and returns null. This
ensures that the default behavior is for control to flow to the first ancestor “case” that
defines a non-trivial processing method. The constants
AadlProcessingSwitch.NOT_DONE and AadlProcessingSwitch.DONE provide
symbolic names for null and a canonical non-null value, respectively, to be used as
return values from “case” methods.
As there is a “switch” class for each Ecore package making up the AADL meta model,
the AadlProcessingSwitch.process(AObject) method is implemented by delegating to
an instance of the appropriate “switch” class based on the class of the given model object.
The class declares a field for each “switch” class, e.g., componentSwitch, flowSwitch,
propertySwitch, etc. Subclasses customize the processing by overriding the method
initSwitches to assign instances of analysis specific subclasses of “switch” classes to
these fields.
Finally, a note on using instances of ForAllAObject and its subclasses. Instances of the
class maintain state during traversals (see Section 4.3 “AADL Model Traversal
Support”). Therefore, a new instance should always be created for each traversal.
3.2.2 The ModelStatistics Code
Our traversal class for the model statistics plug-in, ModelStatistics, extends
AadlProcessingSwitch. The traversal is customized by
9/14/2006
20
• Declaring fields to count the number of occurrences of component types,
component implementations, flow specifications, thread instances, process
instances, etc. These fields are incremented as a side effect of the model traversal
process.
• Overriding initSwitches to create the switches specific to gathering modeling
statistics. This is further described below.
• Declaring additional methods to return the analysis results.
To gather the statistics for a particular model, the plug-in creates a new instance of
ModelStatistics, and then invokes a traversal. For this simple analysis it does not matter
whether a pre-order or a post-order traversal is used. But some analyses might only work
correctly if a specific traversal method is used. Thus it is a good idea to document in the
Javadoc of your traversal class which traversal method is expected to be used.
The class ModelStatistics is shown below. The actual behavior of the model traversal is
declared in the implementation of the method initSwitches, which initializes the switch
fields declared in the super class AadlProcessingSwitch. In particular,
• We provide specific instantiations of CoreSwitch, FlowSwitch, and
InstanceSwitch. It is convenient to provide the switches using Java anonymous
classes.
• We only override those “case” methods that are specifically interesting to our
analysis:
o CoreSwitch.caseComponentType
o CoreSwitch.caseComponentImpl
o FlowSwitch.caseFlowSpec
o FlowSwitch.caseEndToEndFlow
o InstanceSwitch.caseComponentInstance
o InstanceSwitch.caseConnectionInstance
In the implementation below, we implement the method
CoreSwitch.caseComponentType which is called by the switch for each element that is
a subtype of ComponentType. ComponentType is actually an abstract class in the
Ecore model and is the parent class for each specific component type. In our
implementation, we further test the model element against the specific type DataType.
9/14/2006
21
We later discuss an alternative implementation approach that avoids this testing inside of
ComponentType.
The AADL instance model uses ComponentInstance objects to model all categories of
instantiated components. Thus the InstanceSwitch cannot distinguish among the
different categories of instantiated components. Instead we use a Java switch statement
within caseComponentInstance to make this distinction:
switch (obj.getCategory().getValue()) { ... }
The ComponentInstance.getCategory method returns an instance of
ComponentCategory that indicates the component’s category. ComponentCategory
implements the EMF enumeration pattern, [see XXX]. EMF enumerations provide a
canonical object as well as a canonical integer value for each element in the enumeration.
The integer value for a particular enumeration element is retrieved using getValue.
The source code for class ModelStatistics is below. Here we make it a class in the
package edu.cmu.sei.osate.statistics.
package edu.cmu.sei.osate.statistics; import edu.cmu.sei.aadl.model.component.DataType; import edu.cmu.sei.aadl.model.core.ComponentImpl; import edu.cmu.sei.aadl.model.core.ComponentType; import edu.cmu.sei.aadl.model.core.util.CoreSwitch; import edu.cmu.sei.aadl.model.flow.EndToEndFlow; import edu.cmu.sei.aadl.model.flow.FlowSpec; import edu.cmu.sei.aadl.model.flow.util.FlowSwitch; import edu.cmu.sei.aadl.model.instance.ComponentInstance; import edu.cmu.sei.aadl.model.instance.ConnectionInstance; import edu.cmu.sei.aadl.model.instance.util.InstanceSwitch; import edu.cmu.sei.aadl.model.property.ComponentCategory; import edu.cmu.sei.aadl.model.util.AadlProcessingSwitch; public class ModelStatistics extends AadlProcessingSwitch { /* Counters to keep track of occurrences of different * objects in the model. */ private int typeCount = 0; private int componentTypeCount = 0; private int compImplCount = 0; private int threadCount = 0; private int processCount = 0; private int processorCount = 0; private int busCount = 0; private int deviceCount = 0; private int memoryCount = 0; private int componentCount = 0; private int connectionCount = 0; private int flowCount = 0; private int endToEndFlowCount = 0; public ModelStatistics() { super(); }
9/14/2006
22
protected final void initSwitches() { /* We overwrite the case method for a class in the meta model * specific switches. */ // The core switch handles items from the Core package coreSwitch = new CoreSwitch() { /* We want to count all component type declarations. * Thus, we count instances of the abstract ComponentType class. */ public Object caseComponentType(ComponentType obj) { typeCount++; // Only count those that are not DataType if (!(obj instanceof DataType)) componentTypeCount++; return DONE; } public Object caseComponentImpl(ComponentImpl ci) { compImplCount++; return DONE; } }; // We want to count flows, thus, we redefine the FlowSwitch flowSwitch = new FlowSwitch() { public Object caseFlowSpec(FlowSpec obj) { flowCount++; return DONE; } public Object caseEndToEndFlow(EndToEndFlow obj) { endToEndFlowCount++; return DONE; } }; // We want to count instance model objects. instanceSwitch = new InstanceSwitch() { public Object caseComponentInstance(ComponentInstance obj) { componentCount++; /* We want to count category specific instances. We retrieve * the category and branch on its numeric representation. */ switch (obj.getCategory().getValue()) { case ComponentCategory.THREAD: threadCount++; return DONE; case ComponentCategory.PROCESS: processCount++; return DONE; case ComponentCategory.PROCESSOR: processorCount++; return DONE; case ComponentCategory.MEMORY: memoryCount++; return DONE; case ComponentCategory.BUS: busCount++; return DONE; case ComponentCategory.DEVICE: deviceCount++; return DONE;
9/14/2006
23
} return DONE; } public Object caseConnectionInstance(ConnectionInstance ci) { connectionCount++; return DONE; } }; /* Note: we did not redefine processing of elements * from the features or components packages. */ } public String getModelResult() { return "Model Statistics: " + componentTypeCount + " component type declarations, " + compImplCount + " component implementation declarations, " + (typeCount - componentTypeCount) + " data type declarations. "; } public String getFlowResult() { return "Flow Statistics: " + flowCount + " flow specifications, " + endToEndFlowCount + " end-to-end flows. "; } public String getApplicationResult() { if (componentCount > 0) { return "Application statistics: " + threadCount + " threads, " + processCount + " processes, " + connectionCount + " semantic connections. "; } return null; } public String getExecutionPlatformResult() { if (componentCount > 0) { return "Execution platform statistics: " + processorCount + " processors, " + memoryCount + " memory units, " + busCount + " buses, " + deviceCount + " devices. "; } return null; } }
3.2.3 An Alternative Use of Switches
In the method caseComponentType, above, we only increment componentTypeCount
when the model object is not a DataType. Rather than test the types in a conditional, we
could have achieved the same effect by overriding caseComponentType to only
increment typeCount while also overriding the case methods in ComponentSwitch for
all the specific component type classes except DataType to increment the
componentTypeCount field and return NOT_DONE. For example:
coreSwitch = new CoreSwitch() { public Object caseComponentType(ComponentType obj) { typeCount++;
9/14/2006
24
return DONE; } } componentSwitch = new ComponentSwitch() { public Object caseSystemType(SystemType obj) { componentTypeCount++; // We want to fall through to caseComponentType return NOT_DONE; } public Object caseBusType(BusType obj) { componentTypeCount++; // We want to fall through to caseComponentType return NOT_DONE; } // Repeat for all component types except DataType };
We chose not to follow this implementation approach because in addition to being more
verbose, it also makes the intent of the processing less clear.
3.3 Driving the Plug-in
To use our model statistics collection class we need to do several things:
• Make the models statistics functionality available as an Eclipse action. To make
an Eclipse action we need to
o Create a new class that implements the action
o Declare the action to Eclipse in the plug-in’s plugin.xml file.
• Perform the model traversal. The traversal is invoked from a method within the
new class that implements the action.
• Record/report the results. We have several options for making the results
available:
o Associate the results persistently with the model by using Eclipse markers.
Markers are kept with the resource (file) and are shown by Eclipse in the
“Problem” view. Clicking on a marker in this view causes the appropriate
model object to be highlighted in an editor.
o Store the result persistently as an AADL property in the model itself.
o Record the results temporarily with the model through an adapter.
o Store the results in a resource, i.e., file, in the Eclipse project workspace.
o Display the results in a dialog box.
9/14/2006
25
In this example, we illustrate reporting results using markers and using a dialog box.
Section 1 discusses the reporting options in more detail.
3.3.1 Eclipse Actions
We must implement an Eclipse action to make our model statistics functionality available
to the user. We do this in two parts:
1. Implementing a subclass of AaxlReadOnlyAction. This class will execute our
model statistics code.
2. Describing the action in the plug-in’s plugin.xml file.
The OSATE class AaxlReadOnlyAction, in package edu.cmu.sei.osate.ui.actions, is a
convenience class for implementing actions that operate on AADL object models. The
class implements two Eclipse interfaces:
• IWorkbenchWindowActionDelegate allows the action to be invoked from the
Eclipse pull-down menus and toolbar buttons.
• IObjectActionDelegate allows the action to be invoked from context-sensitive
popup menus.
AaxlReadOnlyAction keeps track of the currently selected model object. When the
action is invoked, the implementation
1. Performs sanity checks on the currently selected object
2. Ensures that the necessary Eclipse resources are initialized
3. Delegates to the abstract method doAaxlAction(AObject). The selected model
object is passed to this method.
The intent is that to implement an action, you need only extend AaxlReadOnlyAction
and override the doAaxlAction method.
Class AaxlReadOnlyAction gets its name from the fact that changes made to models as
a side effect of the action will not be saved after the action completes. This allows
actions to make temporary changes to the model to facilitate analyses.
OSATE also provides the abstract class AaxlModifyAction that is the same as
AaxlReadOnlyAction except that it saves any models modified by the action.
Actions implemented as subclasses of AaxlReadOnlyAction or AaxlModifyAction are
invoked by
9/14/2006
26
1. Selecting an .aaxl file in the resource navigator or an AADL model element in
an editor window. When an .aaxl file is selected, doAaxlAction is passed the
root element of the model contained in the file.
2. Clicking on the action’s icon in the Eclipse toolbar or selecting the action’s menu
item.
3.3.2 The Model Statistics Action Code
We define the class DoModelStatistics as a subclass of AaxlReadOnlyAction because it
does not modify the model. Our action is applicable to all AADL model objects:
• If it is invoked on a declarative model object then the statistics of all the
declarative model objects in the Eclipse workspace are computed. That is, all the
declarative specifications, packages, and property sets in all the open projects will
be analyzed.
• If the action is invoked on an instance model object then the statistics of the
containing system instance will be computed together with the statistics of all the
declarative model objects in the workspace.
The first thing the action does is get the root object of the model containing the object obj
passed to the action using the method AObject.getAObjectRoot(). This method returns
an AadlSpec or SystemInstance object depending on whether the object is contained in
an AADL specification or a system instance model. Property sets and package
definitions are also rooted in an AadlSpec object. Our action attaches markers to this
object.
The action next tries to get the SystemInstance, if any, that contains obj using
AObject.getSystemInstance(). When obj comes from an instance model this is the
same object as the model’s root object. When obj comes from a declarative model,
package declaration, or property set declaration this method returns null. Our use of this
method is redundant: we could have performed a type test using instanceof on the object
referenced by root. We include it here, however, for pedagogical purposes.
The action then creates a new ModelStatistics object. We first use the method
processPreOrderAllDeclarativeModels() to analyze all the AADL specifications,
property set declarations, and package declarations in the workspace.1 If the
1 There is also a method processPreOrderAllInstances that traverses all the instance models in the
workspace. Similarly, there are also the methods processPostOrderAllDecls and
processPostOrderAllInstances.
9/14/2006
27
SystemInstance is non-null we have a system instance so we also compute the statistics
of the instance model. The ModelStatistics object now contains the counts of the
various elements in the model.
As mentioned above, we report the results using both Eclipse markers and a dialog box.
To create a marker we simply invoke AaxlReadOnlyAction.reportInfo(AObject,
String). This creates an “informative” marker attached to the given model element with
the given message. In this case, we attach the results to the root model element. We
create one marker for each category of model statistics. We can also create “warning”
and “error” markers using the methods reportWarning and reportError, although we
have no need to do so for this analysis. The action will remove any existing markers
from the model before adding new ones. In general, it is good practice to use a distinct
“marker type” for the results of each plug-in so that your plug-in does not delete the
markers created by other plug-ins. (Update the example to do this.) Section 9 “Persistent
Markers with AADL Models” describes creating and managing markers in more details
as well as how to extend the Model Statistics plug-in to use its own marker type.
Finally, we also report the results in a dialog box. We use the Eclipse Standard Windows
Toolkit (SWT) convenience method openInformation(Shell, String, String) in class
org.eclipse.jface.dialogs.MessageDialog to create and display the modal dialog box:
• The first parameter is the shell—the top-level window in SWT terminonlogy—to
use as the parent of the dialog box. We get this from the action class using the
method AaxlReadOnlyAction.getShell().
• The second parameter is the title of the dialog box.
• The final parameter is the message to display. In our case, the message is our
accumulated list of model statistics results, so we use msg.toString() to convert
the string buffer into a string.
In general, you are free to use SWT to build any kind of window or dialog box you would
like to display the results. A description of how to do so is beyond the scope of this
document. The MessageDialog class provides many additional convenience methods,
e.g., openError, that are suitable for reporting various kinds of analysis results.
The source code for our action class DoModelStatistics is below. We make the class in
package edu.cmu.sei.osate.statistics.
package edu.cmu.sei.ostate.statistics; import org.eclipse.jface.dialogs.MessageDialog;
9/14/2006
28
import edu.cmu.sei.aadl.model.core.AObject; import edu.cmu.sei.aadl.model.instance.SystemInstance; import edu.cmu.sei.osate.ui.actions.AaxlReadOnlyAction; public class DoModelStatistics extends AaxlReadOnlyAction { public void doAaxlAction(AObject obj) { // Get the root object of the model AObject root = obj.getAObjectRoot(); // Get the system instance (if any) SystemInstance si = obj.getSystemInstance(); /* Create a new model statistics analysis object and run it over * the declarative model. If an instance model exists, run it over * that too. */ ModelStatistics stats = new ModelStatistics(); // Analyze all declarative models in the workspace stats.processPreOrderAllDeclarativeModels(); // Analyze the instance model, if we have one if (si != null) { stats.processPreOrderAll(si); } /* Accumulate the results in a StringBuffer, but also report them * using info markers attached to the root model object. */ final StringBuffer msg = new StringBuffer(); final String modelStats = stats.getModelResult(); final String flowStats = stats.getFlowResult(); reportInfo(root, modelStats); reportInfo(root, flowStats); msg.append(modelStats); msg.append(flowStats); if (si != null) { // Do we have instance statistics? final String appStats = stats.getApplicationResult(); final String epStats = stats.getExecutionPlatformResult(); reportInfo(root, appStats); reportInfo(root, epStats); msg.append(appStats); msg.append(epStats); } // Also report the results using a message dialog MessageDialog.openInformation( getShell(), "Model Statistics", msg.toString()); } }
3.4 Creating an Icon for the Plug-in
We should provide an icon our plug-in. Icons are provided as regular image files. The
convention is to use GIF files, although JPEG and PNG format images will also work.
Images files are placed in the Eclipse project just like any other file. They are typically
placed in an icons subdirectory within the project. This directory is easily created within
the project by selection “New | Folder” from the pop-up menu in the “Package
9/14/2006
29
Explorer” view. GIF Files can be copied into this folder using normal drag-and-drop
actions.
Actions have two icons: one for when the action is enabled, and one for when the action
is disabled. If a disabled icon is not provided, Eclipse generates one based on the
provided enabled icon. It is a common practice to base your icon upon existing Eclipse
icons. You can browse existing icons by searching for GIF files in the Eclipse plugins
directory.
We provide both an enabled and disabled icon for the model statistics plug-in. The files
are called stats.gif and noStats.gif, respectively. The resulting structure of the
project is shown in Figure 7.
Figure 7: Structure of the model statistics plug-in project with icon files.
3.5 Describing the Action in the plugin.xml File
Finally, we must describe our action in the plug-in’s plugin.xml file. Our action is to be
runnable from both a toolbar button and a menu item. OSATE plug-ins use normal
Eclipse procedures for describing actions: Actions are grouped into related sets of actions
called “action sets.” Thus before we describe our action, we must describe its action set.
Here we simply describe the declarations necessary to install our action into the
Eclipse/OSATE UI; Section 7 “Writing Eclipse/OSATE Actions” describes these
declarations in more detail. An action set is described using an actionSet XML element
within an extension XML element (within the top-level plugin XML element):
<extension point="org.eclipse.ui.actionSets"> <actionSet id="edu.cmu.sei.osate.statistics.actionSet"
9/14/2006
30
label="Statistics Action Set" visible="true"> </actionSet> </extension>
An action set is always declared as an Eclipse extension point of type
org.eclipse.ui.actionSets. The id, label, and visible attributes of the
actionSet element provide an internal name for the action set, provide a human-
readable label for the action set, and indicate whether the contents of the action set are
initially visible in the Eclipse user interface, respectively.
Because we would like a menu item for our action, we must also describe a menu in
which the action will be located. We use a menu element inside the actionSet:
<menu id="menu.analyses" label="Analyses" path="menu.osate"> <groupMarker name="top.grp"/> <groupMarker name="bottom.grp"/> </menu>
Once again, we give the element an internal id, as well as a human-readable label. This
label is used in the menu bar. The path attribute locates the menu in the menubar, in this
case placing the menu after the menu with the id menu.osate (the “OSATE” menu). We
declare two groups in the menu to which elements can be added; actions added to the
group top.grp will appear before actions added to the group bottom.grp.
We can now describe the action using the action element inside the actionSet:
<action id="edu.cmu.sei.osate.statistics.DoModelStatistics.action" label="Model Statistics" tooltip="Compute model statistics" icon="icons/stats.gif" disabledIcon="icons/noStats.gif" class="edu.cmu.sei.osate.statistics.DoModelStatistics" menubarPath="menu.analyses/top.grp" toolbarPath="statisticsDemo.toolbar" enablesFor="1"> <enablement> <or> <and> <objectClass name="org.eclipse.core.resources.IFile"/> <objectState name="extension" value="aaxl"/> </and> <objectClass name="edu.cmu.sei.aadl.model.core.AObject"/> <objectClass name= "org.eclipse.emf.edit.provider.IWrapperItemProvider"/> </or> </enablement> </action>
An action also has an internal id and label. The label is used to label the action in the
drop-down menu. The tooltip attribute provides a short description of the action be
9/14/2006
31
displayed when the mouse pointer hovers over the toolbar button or menu item. We can
provide icons for the action: the icon and disabledIcon attributes refer to the icons to
use when the action is enabled and disabled, respectively. The path to the image file is
relative to the location of the plugin.xml file. The class attribute names the fully
qualified Java class that implements the action. In this case, that class is
DoModelStatistics.
We locate the action within the user interface. The attribute menubarPath describes in
which drop-down menu the action should appear using the id of the menu element. Here
we locate the action in the top.grp of the previously declared analysisMenu. The
attribute toolbarPath describes where in the toolbar the button for the action is located.
In this case, it is located in a new toolbar with the name statisticsDemo.toolbar. For a
more detailed explanation of toolbar and menu paths see XXX.
Our action should be enabled only when exactly one item is selected in the workspace,
thus we set attribute enablesFor="1". We further refine when the action is enabled by
including within the action element an enablement element that provides a Boolean
expression evaluated over the set of selected items. In this case, our action will be
enabled when any of the three conditions are true (because of the or element):
1. The selected item is an IFile and the filename’s extension is “aaxl.” This
corresponds to selecting a .aaxl file in the “Navigator” or “Package Explorer”
views.
2. The selected item is an EMF Ecore AObject from an AADL model. This
corresponds to selecting an object within an AADL Model editor.
3. The selected item is a wrapped EMF Ecore object. This also corresponds to
selecting an object within an AADL Model editor. Sometimes the editor wraps
the model object, so we need to test against the wrapper as well as against
AObject.
It is a good idea to include an enablement expression in your action description because it
prevents the action from being enabled in situations where it obviously does not apply.
3.5.1 The Complete plugin.xml File
The complete plugin.xml file for the model statistics plug-in should look something like
the following:
<?xml version="1.0" encoding="UTF-8"?> <?eclipse version="3.0"?> <plugin
9/14/2006
32
id="edu.cmu.sei.osate.statistics" name=" Statistics Demo Plug-in" version="1.0.0" provider-name="sei.cmu.edu" class="edu.cmu.sei.osate.statistics.StatisticsPlugin"> <runtime> <library name="statistics.jar"> <export name="*"/> </library> </runtime> <requires> <import plugin="org.eclipse.ui"/> <import plugin="org.eclipse.core.runtime"/> <import plugin="edu.cmu.sei.aadl.model"/> <import plugin="org.eclipse.emf.ecore"/> <import plugin="edu.cmu.sei.osate.ui"/> <import plugin="org.eclipse.core.resources"/> </requires> <extension point="org.eclipse.ui.actionSets"> <actionSet id="edu.cmu.sei.osate.statistics.actionSet" label=" Model Statistics Demo" visible="true"> <menu id="menu.analyses" label="Analyses" path="menu.osate"> <groupMarker name="top.grp"/> <groupMarker name="bottom.grp"/> </menu> <action id="edu.cmu.sei.osate.statistics.DoModelStatistics.action" label="Model Statistics" tooltip="Compute model statistics" icon="icons/stats.gif" disabledIcon="icons/noStats.gif" class="edu.cmu.sei.osate.statistics.DoModelStatistics" menubarPath="menu.analyses/top.grp" toolbarPath="statisticsDemo.toolbar" enablesFor="1"> <enablement> <or> <and> <objectClass name="org.eclipse.core.resources.IFile"/> <objectState name="extension" value="aaxl"/> </and> <objectClass name="edu.cmu.sei.aadl.model.core.AObject"/> <objectClass name="org.eclipse.emf.edit.provider.IWrapperItemProvider"/> </or> </enablement> </action> </actionSet> </extension> </plugin>
9/14/2006
33
3.6 Executing the Model Statistics Plug-in
The simplest way to try out our plug-in is by executing a new Eclipse environment that
loads our new plug-in. Eclipse calls this executing a “Run-time Workbench.” To
execute a run-time workbench
1. Select “Run | Run…” to open the “Run” dialog box.
2. Select “Run-time Workbench” in the “Configurations” list.
3. Click on “New” to create a new run-time workbench configuration. A set of
tabbed panes appears to the right of the list of configurations enabled enabling the
configuration to be customized; see Figure 8.
4. Enter a name for the configuration. Here we have used “Run OSATE Plug-ins.”
5. Choose a directory to use as the workspace for the workbench. Run-time
workspaces have their own independent workspaces. The default workspace is a
sibling of the current workspace: it is named “runtime-workspace” and is in the
same directory as the current workspace.
6. Click on “Run” to execute the newly defined run-time workbench. To save the
changes without running the configuration, click on “Apply” and then “Close.”
9/14/2006
34
Figure 8: Creating a run-time workbench configuration.
To run the configuration select it from the list of configurations and click on “Run.”
Once the configuration has been executed it can be run again by choosing it from the
“Run” toolbar menu, which keeps track of recently executed configurations; see Figure 9.
Simply clicking on the “Run” toolbar icon will reexecute the most recently executed
configuration.
9/14/2006
35
Figure 9: The “Run” toolbar menu.
Figure 10: Choosing which plug-ins to include in the run-time workbench.
By default, the run-time workbench includes all the plug-ins that the host Eclipse
includes, plus those defined by projects in the workspace. You can pick exactly which
plug-ins are included in the run-time workbench using the “Plug-ins” pane; see Figure 10.
Other useful settings when configuring the run-time workbench are “JRE” and “VM
9/14/2006
36
Arguments.” The first lets you specify which Java Runtime Environment (JRE) executes
the run-time workbench, which is useful if you need to make sure your plug-in works
correctly under specific JREs. The menu lets you choose among the JREs that are
currently installed on your system.
Figure 11: Setting the initial and maximum heap sizes of the JVM.
The “VM Arguments” setting allows you to pass arguments to the JVM that executes the
run-time workbench, and is useful for increasing the initial and maximum heap sizes; see
Figure 11. Increasing the maximum heap size is useful when analyzing large models.
The command line options relevant to the heap size and their descriptions (taken from
Sun’s documentation for the java application) are shown below. A complete description
of all the JVM arguments is a beyond the scope of this document.
-Xmsn
Specify the initial size, in bytes, of the memory allocation pool. This value
must be a multiple of 1024 greater than 1MB. Append the letter k or K to
indicate kilobytes, or m or M to indicate megabytes. The default value is
2MB. Examples: -Xms6291456
-Xms6144k
-Xms6m
-Xmxn
Specify the maximum size, in bytes, of the memory allocation pool. This
value must a multiple of 1024 greater than 2MB. Append the letter k or K
to indicate kilobytes, or m or M to indicate megabytes. The default value is
64MB. Examples: -Xmx83886080
-Xmx81920k
-Xmx80m
3.6.1 Model Statistics in Action
As specified in the plug-in manifest file, our model statistics plug-in presents an icon in
the toolbar as well as a menu item in a new “Analysis Menu” menu. Figure 12 and
Figure 13 show examples of the toolbar icon and menu item, respectively. Here we are
running the model statistics plug-in along with other OSATE plug-ins. Observe that all
the plug-in actions appear in the same “Analysis Menu” menu item even though they all
independently declare the menu and their location within it in their respective plug-in
manifest files.
9/14/2006
37
Figure 12: The toolbar icon for our model statistics plug-in. Icon is on the far-right—highlighted in red for clarity—in its
own toolbar.
Figure 13: The menu item for our model statistics plug-in.
As mentioned previously, the model statistics plug-in is executed by first selecting an
AADL model or model element. Until a model or model element is selected, our action
remains disabled in the toolbar and pull-down menu. A model is selected by selecting an
.aaxl file in the “Navigator” view. A model element is selected by selecting it in an
open editor. Then the model statistics action can be executed by clicking on the toolbar
icon or choosing “Model statistics” from the “Analysis Menu.”
Figure 14 shows the results of running the model statistics plug-in over all the declarative
models in the workspace. In this case, we have selected the AADL specification
NotCollocated.aaxl and run the model statistics action. It is a declarative model, so
the declarative contents of the workspace, i.e., the property set SEI.aaxl, and the AADL
specifications NotCollocated.aaxl, Simple.aaxl, and TestAllowed.aaxl are
analyzed; the instance model Simple_S_packable_Instance.aaxl is not analyzed. The
results are shown as markers in the “Problems” view. The dialog box reporting the same
results is shown in Figure 15.
9/14/2006
38
Figure 14: Markers (in the “Problems” view) recording the model statistics for the declarative models in the workspace,
i.e., the models in project “TestBinPackerMultiFile.”
Figure 15: Dialog box reporting the model statistics for the AADL workspace shown in Figure 14.
Figure 16 shows the results of running the model statistics plug-in over the instance
model in Simple_S_packable_Instance.aaxl. In this case, we opened the model in an
editor, selected the root node of the model and then executed the model statistics action.
The dialog box reporting the same results is shown in Figure 17.
9/14/2006
39
Figure 16: Markers (in the “Problems” view) recording the model statistics for the instance model “Simple_S_Instance.”
Figure 17: Dialog box reporting the model statistics for the AADL instance model shown in Figure 16.
3.7 Deploying Model Statistics
Finally, now that we have tested our plug-in, we would like to make it available for
others to use. The simplest way to do this is to create a zip file that contains the plug-in
and its supporting files that others can unzip into their Eclipse installation. Before we can
do this, we must configure the build properties of the plug-in. This is done by editing the
plug-in’s plugin.xml file, and opening the “build” pane. (This pane actually edits the
build.properties file, which can be edited directly using the “build.properties” pane.)
The editor pane for our model statistics plug-in is shown in Figure 18. We need to tell
Eclipse what to include from the project with our plug-in besides a jar file containing the
9/14/2006
40
class files. The “Binary Build” section of the pane allows you to check off which
files/folders should be included. You should always include the plugin.xml file because
it describes the plug-in to Eclipse. Here we also check-off the icons directory so that the
icons for our action are included. We do not need to include the bin directory because
Eclipse will already include the class files in a jar file (in this case, one named
statistics.jar).
Figure 18: Editing the build properties of the model statistics plug-in.
To create the zip file of the plug-in, select “File | Export…” and then choose
“Deployable plug-ins and fragments.” You are then presented with the “Export Plug-ins
and Fragments” dialog, as shown in Figure 19. In the top portion of the dialog, we select
which plug-in projects to export; in this case, only the model statistics plug-in
edu.cmu.sei.osate.statistics. We choose to deploy it as “a single ZIP file” to be written
to the desktop. Click on “Finish” to write the zip file.
9/14/2006
41
The zip file StatisticsPlugin.zip can now be distributed. To install the plug-in for it,
simply unzip the archive into the root directory of an Eclipse installation.
Figure 19: Exporting the model statistics plug-in as a zip file.
3.8 Summary of Concepts
This section describes how to create a simple plug-in for OSATE that counts the number
of components in an AADL model. Creating a plug-in requires knowledge about Eclipse,
the AADL meta model, and the OSATE APIs. Here we close the section with a brief
summary of the major topics.
9/14/2006
42
3.8.1 Eclipse
An OSATE plug-in is written as an Eclipse plug-in project. Plug-in projects have a
plugin.xml file that describes the appearance and structure of the plug-in. We use it to
declare our plug-in’s dependencies on other plug-ins, to declare an Eclipse action, and to
declare an Eclipse action set to contain our action in the Eclipse user interface. Section 7
“Writing Eclipse/OSATE Actions” describes creating actions and integrating them with
the Eclipse/OSATE, as well as how to create deployable plug-ins, features, and update
sites.
By default, a plug-in depends on the plug-ins org.eclipse.ui and
org.eclipse.core.runtime. An OSATE plug-in should also declare that it depends on
edu.cmu.sei.aadl.model and org.eclipse.emf.ecore so that it can use the AADL meta
model, and edu.cmu.sei.osate.ui so that it can access the abstract action
implementations..
Our plug-in uses Eclipse’s SWT framework to open a simple dialog box to display
results. The static method MessageDialog.openInformation() display a simple dialog
box displaying information results. Class MessageDialog also has the methods
openError and openWarning, among others, that are useful for interacting with users of
a plug-in.
3.8.2 Meta Model
The AADL meta model is modeled using the Eclipse Modeling Framework (EMF). The
model is split across seven EMF Ecore packages: core, component, connection, feature,
flow, instance, and property. These package correspond to a suite of Java packages
edu.cmu.sei.aadl.model.core, edu.cmu.sei.aadl.model.core.impl,
edu.cmu.sei.aadl.model.core.util, edu.cmu.sei.aadl.model.component,
edu.cmu.sei.aadl.model.component.impl, edu.cmu.sei.aadl.model.component.util,
edu.cmu.sei.aadl.model.connection, edu.cmu.sei.aadl.model.connection.impl,
edu.cmu.sei.aadl.model.connection.util, etc. that are in the Eclipse plug-in
edu.cmu.sei.aadl.model.
EMF generates a “switch” class for each Ecore package. This class is in the
corresponding Java util package, and contains a “case” method for each class declared in
the package. The case methods understand the class hierarchy, and “fall through” to
super classes if the case method returns null. OSATE provides a compound switch class
edu.cmu.sei.aadl.model.util.AadlProcessingSwitch that coordinates the use of switches
9/14/2006
43
across all the Ecore packages as well as including model traversal functionality (see
below).
This section does not cover the meta model in any depth, but the model statistics plug-in
tests against the ComponentType and ComponentImpl classes, which are the super
types of the more specific component type and component implementation classes,
respectively. The model statistics plug-in counts the different categories of instantiated
components in the instance model. Unlike the declarative model, which has a different
class for each component category, the instance model has only one class for representing
an instantiated component: ComponentInstance. To determine the category of the
component, the “category” attribute must be consulted using
ComponentInstance.getCategory(). This method returns an instance of
ComponentyCategory, a class that implements the EMF enumeration pattern. In
actuality, we test against the integer values of the enumeration elements using a normal
Java switch statement:
switch (obj.getCategery().getValue() { case ComponentCategory.THREAD: … break; case ComponentCategory.PROCESS: … break; // etc. }
3.8.3 OSATE API
The OSATE API provides many classes that customize the functionality of Eclipse and
EMF APIs to better support AADL models. The class
edu.cmu.sei.aadl.model.util.ForAllAObject encapsulates model traversal functionality.
The model statistics plug-in uses the traversal method processPreOrderAll to perform
pre-order traversals starting at a specific root object and the traversal method
processPreOrderAllDeclarativeModels to perform a pre-order traversal of all the
declarative model structures in the Eclipse workspace. This class is described in more
detail in Section 4.3 “AADL Model Traversal Support.” The model statistics analysis is
implemented as an extension of the class AadlProcessingSwitch, a subclass of
ForAllAObject, that delegates to EMF switch classes as the models are traversed. The
method initSwitches is overridden to create to appropriate switch class implementations
for the analysis.
OSATE provides implementations of IWorkbenchWindowActionDelegate that make it
easier to create an OSATE-specific action. The class
9/14/2006
44
edu.cmu.sei.osate.ui.actions.AaxlReadOnlyAction is extended to define an action that
does not persist any changes made to models as a side-effect of the action. The class
AaxlModifyAction, a subclass of AaxlReadOnlyAction, does persist changes made as a
side-effect. In either case, the body of the action is defined by implementing the method
doAaxlAction(AObject o) that is passed the currently selected model object.
AaxlReadOnlyAction also defines methods that make it simple to deposit markers on
model objects for result reporting: reportInfo, reportWarning, and reportError.
These methods take as parameters the model object on which to place the marker and the
string message to associate with the marker. See Section 9 “Persistent Markers with
AADL Models” for more information.
9/14/2006
45
4 Processing of AADL Models This section is still true, but there are new topics that should be added: default traversals, methods
for batching together traversal execution, cancelling traversals, etc.
This note discusses support for processing AADL models. After a short summary of the
three types of models, the section discusses processing support based on various forms of
traversal of declarative AADL models as well as AADL instance models. These methods
are the basis for many analysis and generation plug-ins to OSATE that process AADL
models but do not change the models. This is followed by a discussion of methods that
manipulate the models, i.e., make changes to the models.
4.1 Meta Model Defined AADL Models
The AADL meta model defines the structure of AADL models, i.e., an object
representation of AADL specifications that corresponds to a semantically decorated
abstract syntax tree. The object representation of AADL models can be manipulated
programmatically through an API. The object representation of AADL models can also
be persistently stored as XML documents in an interchangeable manner by different tools
that support AADL by adhering to an XML schema or XMI meta model specification.
Both of these are derived from the AADL meta model.
Three model representations and persistent XML formats of AADL models have been
identified:
• A declarative AADL model: AADL specifications in form of component types,
component implementations, port group types, annex libraries, packages
organizing these declarations, and property sets introducing additional property
types, property constants, and property names.
• A graphical layout model: Layout information for the graphical display of AADL
models. The graphical layout representation is associated with AADL models in
their declarative representation and instance model.
• An AADL instance model: A compact representation of a system instance whose
root is a system implementation in an AADL specification. This model contains
AADL properties relevant for backend processing. Declarative information is
accessible, if needed, through cross-document references to the declarative model.
Figure 20 shows the three model representations and their relationship to the textual and
graphical AADL representation as well as to tools that process and analyze AADL
models.
9/14/2006
46
The declarative AADL model reflects AADL specifications and supports translation from
and to the textual AADL representation. A parser translates text into a declarative AADL
model. Name resolution, semantic checking and other static analysis can be performed
on this in-core object model of the declarative AADL model. Results of such analysis
can be recorded in the declarative AADL model as property values. This makes analysis
results available in a standard format for other analysis and for generation tools as
illustrated in Figure 20. An XML-to-Text converter can reproduce textual AADL from
the declarative AADL model.
The graphical AADL model is supported by graphical editing tools operating on the
declarative AADL model and using the graphical layout model to maintain relevant
layout information about the AADL model. Graphical presentation of AADL instances is
supported in a similar manner.
The declarative AADL model contains information that is relevant to assure the semantic
consistency of AADL models. However, this information is often not relevant to
backend analyses and runtime system generation. Therefore, a more compact AADL
instance model is desirable that is tailored to such processing. This AADL instance
model is derived from the declarative AADL model. It is used by analyses of system
instances, in many cases analyses that require a system model in which application
components are bound to execution platform components. Such analysis tools may
operate on an in-core object representation of the AADL instance model directly, or
filters convert this representation into an analysis tool specific representation. Results
from such analysis can be recorded as properties in the AADL instance model and
mapped back into the declarative AADL model as necessary.
9/14/2006
47
Figure 20 AADL Models and Tools
A full discussion of the AADL Meta Model and the interchange format can be found in
Annex D of the SAE AADL Standard [SAE AADL 2005]. In the context of this note we will
refer to the meta model class AObject that is the common super class of all AADL model
objects and to InstanceObject as the common super class of all instance model objects.
4.2 Notes on Accessing Models
The AADL meta model defines attributes for classes in the meta model as well as
containment and reference associations between classes. Attributes are pieces of
information stored in an object of an AADL model itself. An example attribute is the
“timing” attribute of the DataConnection class in Figure 21. The association
“eventConnection” is a containment association between the Connections and
EventConnection class in Figure 21. The association “refines” is a reference
association between two AADL model objects of the class EventConnection in Figure
21. Attributes, containments, and references can be single valued (shown by an indicator
of 0..1 or 1), or they can be multi-valued (shown by an indicator whose upper bound is
greater than 1 with * indicating an arbitrary number).
4.2.1 An API for Accessing AADL Models
EMF generates a collection of methods for accessing and changing AADL models. The
API for accessing AADL models consists of a collection of “getter” methods. These
methods have the name get and the name of the attribute, containment, or reference to be
accessed. For example, the method getRefines() provides access from an
EventConnection object to the EventConnection object it refines. Reference
associations automatically handle references between objects stored in different XML
documents. If an attribute, containment, or reference is multi-valued, then the get
method returns a list object that implements the interface
org.eclipse.emf.common.util.EList. The EList interface extends the Java Collections
interface java.util.List, adding methods to move elements within the list (see EMF book
for more detail).
The API for changing the model consists of “setter” methods. For single values these
methods have the name set and the name of the attribute, containment, or reference to be
changed. For multi-valued attributes, containment, and references these methods have
the name add and the name of the attribute, containment, or reference to be added to the
multiplicity list. The multi-value list can also be retrieved with the getter method and
cleared.
9/14/2006
48
Some classes have a set of containment associations to concrete classes that represent
different categories of an abstract class. In the meta model shown in Figure 21, the class
Connections contains EventConnection objects, DataConnection objects, etc. under
separate containment associations. As a result, the contained XML elements have tag
names that correspond to the containment label. Although they have separate
containment associations, they represent a collection of connections. An EMF provided
method eContents() returns the objects of all containment associations of an AADL
model object. An EMF feature map has been specified in the meta model (see [AADL
Meta Model Annex]). This feature map maintains an ordering of all contained objects
across the containment associations. This assures that the order in which connection
objects are added to a model is the same order in which they are returned by eContents().
In the case of a parsed AADL model, this order is the declaration order encountered in
the textual AADL model.
These methods are straightforward implementations and strictly follow the structure of
the model. While in many cases these methods are perfectly adequate, we have
introduced additional convenience methods into the API.
4.2.2 Eliding Model Structure
The meta model includes structural information that is sometimes not interesting to
clients of the model. For example, consider class ComponentImpl in Figure 21: it has a
“connections” containment that refers to a Connections object, which in turn, has the
containments labeled “dataAccessConnection,” “busAccessConnection,”
“parameterConnection,” “eventConnection,” etc. That is, there is an additional layer of
abstraction between a component implementation and its connections that represents the
connections subclause of the component implementation. This applies to all subclauses
of classifiers.
9/14/2006
49
Figure 21: Portion of meta model hierarchy showing extra level of indirection in the representation of connections.
Note that the classes referenced by Connections are all subclasses of Connection.
Some processing of AADL models can be performed for all classifiers, component types,
or component implementations and the same processing is done for all elements of each
subclause. In this case the processing methods want to retrieve all elements of a
component type or component implementation subclause, i.e., all connections of a
component implementation in our example, directly.
For this reason we have provided convenience methods for the classes Classifier,
ComponentClassifier, ComponentType, and ComponentImpl. For example, in
addition to the method ComponentImpl.getConnections() that returns the Connections
object, ComponentImpl has the method getConnection() that returns an EList of
Connection objects representing the connection declarations and refinements specified in
the component implementation.
4.2.3 AADL Inheritance Semantics
The meta model generated getter methods do not understand the inheritance semantics of
AADL. For example, when retrieving the connections in a component implementation,
analysis is often interested in the connections declared in that component implementation
together with the connections defined in any ancestor component implementations. In
9/14/2006
50
addition, if an ancestor connection is refined, only the declaration of the refinement is
interesting. However, the meta model only captures the syntactic structure of the AADL
model. The connections referenced by the Connections model object are thus only those
connections declared within the associated component implementation. We thus have the
convention that a normal meta model get method returns only those elements that are
locally declared within a component, and that an additional getAll method returns all
elements that are visible in the component due to inheritance, taking refinement into
account. Be aware that not all getAll methods return lists: some attributes are
“inheritable” via feature refinement, but they instead fill in previously unspecified
information, for example, the component classifier of a subprogram feature.
This naming convention combines with the previous convention: continuing with the
connections example, ComponentImpl also has the method getAllConnection() that
returns an EList of Connection objects representing all the connections visible in the
component implementation, including those inherited from ancestor component
implementations.
4.2.4 Specialized Reference Associations
In some cases the meta model has containment or reference associations defined for
abstract classes that are specialized as containment or reference associations with the
same label for concrete subclasses. For example, all the subclasses of ComponentImpl
declare a “subcomponents” containment. This abstract containment association is
denoted in the meta model via a dashed line; see Figure 22. Example specializations of
this “subcomponents” containment association are shown in Figure 23: DataImpl’s
“subcomponents” attribute refers to a DataSubcomponents object, ThreadImpl’s
“subcomponents” attribute refers to a ThreadSubcomponents object, etc.
Because EMF does not support “abstract” associations and their specializations, no
access methods are automatically generated. Even if the appropriate access methods are
added to the abstract classes—in our example to ComponentImpl—Java 1.4 would
complain about incompatible return types because subclasses cannot refine the return
value of a method. In our case, the return value of the access method
getSubcomponents() of the subclass DataImpl would return DataSubcomponents, but
the access method would have to be declared in ComponentImpl to return an instance of
Subcomponents.
9/14/2006
51
Figure 22: Portion of meta model showing the abstract “subcomponent” attribute between ComponentImpl and
Subcomponents.
Figure 23: Portion of meta model showing DataImpl and ThreadImpl's specific “subcomponents” attributes. This
excerpt does not show the fact that DataSubcomponents and ThreadSubcomponents are subclasses of
Subcomponents.
To get around this problem, we have a third naming convention: we use getX methods to
name generic getter methods in super classes. Again, this convention combines with the
two previously described conventions. Thus ComponentImpl has the method
getXSubcomponents() that returns a Subcomponents object (the super class of
DataSubcomponents, ThreadSubcomponents, etc.), as well as the methods
getXSubcomponent() and getXAllSubcomponent() that each return an EList of
Subcomponent objects.
Note: Java 1.5 fixes this problem by allowing covariant return types on overridden
methods.
4.2.5 Unifying “Either-Or” Associations
In a few cases a class in the meta model has a reference and containment association
where only one of the two is expected to be set. For example, NumberType has a
reference association “unitsTypeReference” and a containment association “unitsType”.
These two associations come about because the AADL syntax allows the declaration of a
number type to either reference a declared units type or specify the unit type in-place
9/14/2006
52
within the number type declaration. Thus to get the unit type from a NumberType, you
have to check both associations and use which ever is non-null. This is verbose and error
prone, so the naming pattern getThe is used to name a single method that returns which
ever association is non-null. For example, NumberType has the method
getTheUnitsType().
4.2.6 Specific Instances of the Getter Method Patterns
4.2.6.1 Package edu.cmu.sei.aadl.model.core
Class Attribute Additional Methods
Abstract “features” getXAllFeature ComponentClassifier
Abstract “extends” getXExtend
getXAllCallSequence
getXCallSequence Abstract
“callSequences” getXCallSequences
getAllConnection
getAllConnection(Mode)
getConnection “connections”
getConnection(Mode)
getXAllFeature Abstract “features”
getXAllAbstractPort
getAllFlowSequence
getAllFlowSequence(Mode)
getFlowSequence “flows”
getFlowSequence(Mode)
getAllMode
getAllModeAndModeTransition
getAllModeTransition
getMode
getModeAndModeTransition
“modes”
getModeTransition
“refinesType” getAllRefinedFeature
getXAllSubcomponent
getXAllSubcomponent(Mode)
getXSubcomponent
ComponentImpl
Abstract
“subcomponents”
getXSubcomponent(Mode)
9/14/2006
53
Class Attribute Additional Methods
getXSubcomponents
getXAllFeature
getXFeature Abstract “feature”
getXFeatures
getAllFlowSpec
ComponentType
“flowSpecs” getFlowSpec
getXAllDst Abstract “dst”
getXDst
getDstContext “dstContext”
getAllDstContext
Abstract “refines” getXRefines
getXAllSrc Abstract “src”
getXSrc
getSrcContext
Connection
“srcContext” getAllSrcContext
getXAllDataClassifier Abstract
“dataClassifier” getXDataClassifier Feature
Abstract “refines” getXRefines
PropertyHolder “properties” getPropertyAssociation
Abstract “classifier” getXClassifier
getXAllAbstractPort Abstract “feature”
getXAllFeature Subcomponent
Abstract “refines” getXRefines
4.2.6.2 Package edu.cmu.sei.aadl.model.feature
Class Attribute Additional Methods
BusAccess “busClassifier” getAllBusClassifier
DataAccess “dataClassifier” getAllDataClassifier
Parameter “direction” getAllDirection
Port “direction” getAllDirection
getAllFeature PortGroupType “feature”
getFeature
ServerSubprogram “subprogramClassifier” getAllSubprogramClassifier
Subprogram “subprogramClassifier” getAllSubprogramClassifier
9/14/2006
54
4.2.6.3 Package edu.cmu.sei.aadl.model.flow
Class Attribute Additional Methods
getXAllImplement FlowImpl Abstract “implement”
getXImplement
getXAllDst Abstract “dst”
getXDst
getXAllDstContext Abstract “dstContext”
getXDstContext
getXAllSrc Abstract “src”
getXSrc
getXAllSrcContext
FlowSpec
Abstract “srcContext” getXSrcContext
4.2.6.4 Package edu.cmu.sei.aadl.model.instance
Class Attribute Additional Methods
ComponentInstance Abstract “componentImpl” getXComponentImpl
4.2.6.5 Package edu.cmu.sei.aadl.model.property
Class Attribute Additional Methods
“unitsType” NumberType
“unitsTypeReference” getTheUnitsType
NumberValue Abstract “value” getXValue
“propertyType” PropertyConstant
“propertyTypeReference” getThePropertyType
“propertyType” PropertyDefinition
“propertyTypeReference” getThePropertyType
“numberType” RangeType
“numberTypeReference” getTheNumberType
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
9/14/2006
55
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. This functionality is introduced in Section 4.3.5 “Reporting Markers
During a Traversal” and described in more detail in Section 9 “Persistent Markers with
AADL Models.”
The intent is that a new instance of ForAllAObject, or more specifically, of an analysis-
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.
4.3.1.1 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.
9/14/2006
56
4.3.1.2 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).
4.3.1.3 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()); }
9/14/2006
57
};
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);
4.3.1.4 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.
4.3.1.5 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. We have provided two
capabilities for processing of such lists of AObjects:
• QuickSort for sorting ELists of AObjects.
9/14/2006
58
• processEList for processing ELists of AObjects with the same tailorable
filtering and action methods that are part of the traversal support.
4.3.1.5.1 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.
This 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);
4.3.1.5.2 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
9/14/2006
59
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 based on the meta-model’s containment
relationships. 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.
4.3.2.1 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
9/14/2006
60
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.
4.3.2.2 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
9/14/2006
61
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.
4.3.2.3 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
9/14/2006
62
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.
4.3.2.4 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.
9/14/2006
63
• 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
9/14/2006
64
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 situations 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 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 null. Given a null return value, the switch processing
method invokes the “case” method of each super class in turn until a “case” method
returns a non-null value or the “case” method of the common super class has completed.
OSATE declares canonical values to use for these purposes:
AadlProcessingSwitch.NOT_DONE and AadlProcessingSwitch.DONE, respectively.
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.
9/14/2006
65
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.
4.3.4.1 Traversal-Driven Switch Processing
Traversal-driven switch processing involves two steps:
1. The specification of meta model class specific processing actions by redefining
the appropriate “case” methods in the meta model package specific switches
2. 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 Section 3.2.2 “The ModelStatistics Code” is a prime example
of the use of traversal-driven switch processing because 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.
4.3.4.1.1 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.
9/14/2006
66
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; // ... protected final void initSwitches() { // ... flowSwitch = new FlowSwitch() { public Object caseFlowSpec(FlowSpec obj) { flowCount++; return DONE; } public Object caseEndToEndFlow(EndToEndFlow obj) { endToEndFlowCount++; return DONE; } }; } }
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. Section 4.3.4.2 “Content-Driven Switch Processing” shows how interleaved
processing can be achieved.
4.3.4.1.2 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 Section 3.3.2 “The Model
9/14/2006
67
Statistics Action Code.” We need to use a different traversal method depending on
whether the action is invoked on an instance model or a declarative model. The action
tries to get the instance model that contains the object obj passed to the action using the
method AObject.getSystemInstance(). If this method returns a non-null value, then we
invoke a traversal over that system instance using
ForAllAObject.processPreOrderAll(AObject). Otherwise, we invoke a traversal over
all the declarative models in the workspace using the method
ForAllAObject.processPreOrderAllDeclarativeModels().
// Get the system instance (if any) final SystemInstance si = obj.getSystemInstance(); /* Create a new model statistics analysis object. Run it over the * instance model if it exists. Otherwise, run it over all the * declarative models in the workspace. */ final ModelStatistics stats = new ModelStatistics(); if (si != null) { stats.processPreOrderAll(si); } else { stats.processPreOrderAllDeclarativeModels(); }
4.3.4.2 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.
4.3.4.2.1 Controlling the Invocation of the Super Class Case Method
There are 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
9/14/2006
68
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.
4.3.4.2.2 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.
4.3.4.2.3 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 ways to accomplish 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.
9/14/2006
69
• 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.
4.3.5 Reporting Markers During a Traversal
In Section 3.3.2 “The Model Statistics Action Code,” we introduce the methods
reportInfo, reportWarning, and reportError in the class AaxlReadOnlyAction.
These methods allow a plug-in to log markers in the Eclipse “Problems” view. When
writing an analysis as a traversal, it is often convenient to report analysis results as they
are discovered during the traversal. To this end, the class ForAllAObject also declares
methods reportInfo, reportWarning, and reportError. For both
AaxlReadOnlyAction and ForAllAObject these methods are implemented by
delegating to a edu.cmu.sei.aadl.model.pluginsupport.MarkerReporter object. The
MarkerReporter object is created by AaxlReadOnlyAction when the action is invoked.
9/14/2006
70
ForAllAObject and AadlProcessingSwitch have two constructors each: one that takes
no arguments, and one that takes a MarkerReporter object. The no-argument
constructor initializes the traversal with a the default reporter,
MarkerReporter.defaultReporter. The default reporter prints the markers to the
standard ouput instead of creating markers in the “Problems” view. Within a subclass of
ForAllAObject the reporter instance can be accessed using the protected final field
reporter. Usually you want the traversal to use the marker reporter created by the action
that invokes it. The method AaxlReadOnlyAction.getMarkerReporter() returns the
MarkerReporter created by the action. Thus a typical traversal implementation has a
constructor that takes a MarkerReporter:
public class MyTraversal extends ForAllAObject { public MyTraversal(final MarkerReporter reporter) { super(reporter); } protected void action(final AObject obj) { if (...) { reportWarning(obj, "Warning Message"); } } // ... }
And a typical traversal creation resembles the following:
public class MyAction extends AaxlReadOnlyAction { // ... public void doAaxlAction(final AObject obj) { // ... final MyTraversal myT = new MyTraversal(this.getMarkerReporter()); // ... } }
Marker management is described in detail in Section 9 “Persistent Markers with AADL
Models.”
4.4 AADL Model Manipulation Support
This section seems out of place and incomplete?
This section discusses three forms of AADL model manipulation:
• Recording of plug-in processing results as AADL property values in the model
being processed; the declarative AADL model or the AADL instance model is not
modified other than by associating AADL property values to AADL model
objects.
9/14/2006
71
• Modification of the model being processed or creation of a new model; a
declarative AADL model or an AADL instance model is manipulated directly and
the modifications will result in any listener of the model to be notified of the
changes. Deep-copy methods provide for cloning of models in order to support
what-if processing based on changed models.
• Modification of the model through EMF generated edit commands; a declarative
AADL model or an AADL instance model is manipulated through undoable
commands and the command history support reversing the model changes. Model
listeners are notified of model changes—as above. The command-based model
modification provides for a more incremental form of what-if processing of
models.
9/14/2006
73
5 Processing AADL Properties This section is correct, but should have information about the PropertyUtils class added to it.
AADL components may contain property values. These values provide information
about the component. Properties are declared, as part of an AADL specification, in
property sets. Properties can be declared to support specific analyses, to be used both as
inputs to the analysis, and to record the results of analysis. This section introduces
AADL properties, describes how to declare new properties in an AADL specification,
describes how to associate property values with components in an AADL specification,
and then describes how to access and manipulate property values using the AADL meta
model and OSATE. A security level plug-in is used as a running example. Chapter 10 of
the AADL Specification describes the semantics of AADL properties in detail.
Many of the following sections discuss the syntax and semantics of AADL beyond the
coverage normally given to these issues in this plug-in guide. This is because to use
properties in a plug-in requires that new properties be declared for use in a specification,
and thus the plug-in writer must know how to do this. Also, the explanations uncover
intricacies of AADL properties that motivate similar intricacies in the resulting properties
API provided by OSATE.
5.1 The Security Level Plug-in
As an example of using properties in a plug-in, this section describes the implementation
of a “security level” plug-in. Property associations are used to assign a security level to
each component in a specification. We declare a new SecurityLevel property for this
purpose. This analysis can be applied after assigning a security level to each component
in a specification. The analysis checks that a component only contains components
whose security level is less than its own, and that connections only flow from lower level
components to higher level components. In addition, the analysis will infer the least
upper bound on the security level necessary for components not explicitly given a
security level.
5.2 An Overview of AADL Properties
An AADL property provides information about an element of an AADL specification.
For example, properties are used to provide the period of a thread, the latency of a
connection, or the size of data. A property has a name and a type; only values of the
appropriate type can be associated with a property. Properties are declared in named
9/14/2006
74
property sets. Property associations in component declarations assign a particular
property value to a particular property for a particular component.
A property set contains three kinds of declarations:
1. Property type declarations
2. Property constant declarations
3. Property name—or simply “property”—declarations
For example, the AADL specification below declares a property set named Example that
contains two property type declarations, one property constant declaration, and a property
declaration. Specifically, the property set first declares the unit type English_Units,
which contains three elements inch, foot, and yard. The second type, Length, is
declared to be integers labeled by units from English_Units. The property constant
One_Foot is of type Length, and has the value 1 foot. Finally, the property
Documentation_Thickness is declared. It has values of type Length, and a default
value of One_Foot. Furthermore, only processor, bus, and system components can
associate values with this property.
property set Example is -- Unit Type declaration English_Units: type units (inch, foot => inch * 12, yard => foot * 3); -- Integer type declaration Length: type aadlinteger units Example::English_Units; -- Constant declaration One_Foot: constant Example::Length => 1 foot; -- Property declaration Documentation_Thickness: Example::Length => value(Example::One_Foot) applies to (processor, bus, system); end Example;
This section provides an overview of AADL property types and property declarations
intended to assist the producers of analyses in understanding what kind of properties can
be expressed for use by analyses. We do not consider property constants any further
except for how they impact the meta model. The reader is referred to Chapter 10 of the
AADL Specification for more information.
5.2.1 AADL Property Types
Property types constrain the values that can be associated with a property. There are nine
kinds of property types:
9/14/2006
75
• The aadlboolean property type represents Boolean values and has two values:
true and false. AADL supports Boolean arithmetic with aadlboolean values.
• The aadlstring property type represents string values such as "A String Value".
• The enumeration property type represents an explicitly listed set of identifiers as
its set of legal values. For example, the type enumeration (red, green, blue) has
the values red, green, and blue.
• The units property type represents an explicitly listed set of measurement unit
identifiers, and declares their relationships. For example, the type units (inch,
foot => inch * 12, yard => foot * 3) declares three measurement unit identifiers,
and declares that a foot is equivalent to 12 inch units, and that a yard is
equivalent to 3 foot units, or equivalently, 36 inch units. Below we discuss how
the meta model and OSATE handle unit conversions. A units property type does
not have values: it can only be used in the specification of aadlinteger and
aadlreal types.
• The aadlinteger property type represents an integer value or an integer value with
a measurement unit. If the type specifies a unit type, then the value must be
labled with a measurement unit from the specified unit type. An optional range
may also be specified that further constrains the legal property values; if the type
specifies a unit type, then the bounds of range must be labeled with units. The
following are examples of legal aadlinteger property types:
o The type aadlinteger includes the values -100, 0, 45, 10000, etc.
o The type aadlinteger 0 .. 10 has the values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, and
10.
o The type aadlinteger units (cm, m => cm * 100) includes the values -
5 cm, -3 m, 0 m, 200 cm, etc.
o The type aadlinteger 5 foot .. 10 yard units Example::English_Units
includes the values 5 foot, 61 inch, 2 yard, 30 foot, and 360 inch. The
values 59 inch and 31 foot, however, are not assignable to properties of
this type because they are outside the allowable range of values.
The type aadlinteger 0 .. 100 units (cm, m => cm * 100) is illegal because the
range bounds 0 .. 100 do not have measurement units specified, and thus the true
range of values is ambiguous.
9/14/2006
76
The maximum integer value expressible as a property value is bounded by the
property constant AADL_Project::Max_Aadlinteger. In OSATE, integer values
are represented by Java long values, and thus aadlinteger values are limited to
twos-complement 64-bit integers. This is not to be confused with the largest
integer value supported by the application system.
• The aadreal property type represents a real value or a real value with a
measurement unit. Otherwise it is similar to the aadlinteger property type. In
OSATE, real values are represented by Java double values, which are double-
precision 64-bit format IEEE 754 values. Again, this representation has nothing
to do with the floating point values that may or may not be supported in the
system being modeled.
• The range type represents closed intervals of numbers. It specifies that a property
of this type has a value that is a range term. The bounds on the specifiable ranges
are given by an aadlreal or aadlinteger type. A range term consists of a lower
bound, an upper bound, and an optional delta that gives the distance between
adjacent values in the range. The following are examples of legal range types:
o The type range of aadlinteger includes the values -10 .. 10, -
10 .. 10 delta 2, 5 .. 7, etc.
o The type range of aadlreal 0.0 .. 10.0 includes the values
0.5 .. 9.0 delta 0.1, 9.0 .. 10.0, and 0.0 .. 10.0. The value 5.0 .. 11.0 is not
assignable to properties of this type because it bounds are not contained
within 0.0 .. 10.0.
o The type range of aadlinteger 5 foot .. 10 yard units
Example::English_Units includes the values 5 foot .. 7 foot delta 6 inch,
5 yard .. 10 yard delta 1 foot, and 60 inch .. 360 inch. The value
9 yard .. 31 foot is not assignable to properties of this type because its
upper bound is out of range.
o The type range of Example::Length does include 9 yard .. 31 foot
because the type does not have any bounds on the range bounds.
• The classifier property type represents the subset of syntactically legal component
classifier references whose category matches one of the component categories in
the specified list. If the category list is absent, all component classifier references
are acceptable. The following are examples of classifier types and their values:
9/14/2006
77
o The type classifier (processor) includes all processor type and processor
implementation classifiers.
o The type classifier (thread, process) includes all thread type, process
type, thread implementation, and process implementation classifiers.
o The type classifier includes all component classifiers.
• The reference property type represents the subset of syntactically legal references
to those components whose category matches one of the component categories,
connections, or server subprogram features in the specified list. If the category
list is absent, all components, connections, and server subprograms are
acceptable.
It is easy to confuse classifier and reference types. The distinction is that the values of
classifier types are the names of component types or implementations whereas the values
of references types are specific subcomponents, connections, or features in a system
specification. The difference is highlighted in the following example:
property set ps is classifierType: type classifier (system); referenceType: type reference (system); classifierProp: ps::classifierType applies to (all); referenceProp: ps::referenceType applies to (all); end ps; system Inner end Inner; system Outer end Outer; system implementation Outer.Impl subcomponents innerSubComponent: system Inner; properties ps::classifierProp => system Inner; ps::referenceProp => reference innerSubComponent; end Outer.Impl;
Property values can also be lists whose members are restricted to be values of a particular
property type. The AADL Specification considers “listness” to be an attribute of the
property declaration, not of the property type.
5.2.2 AADL Property Declarations
AADL property declarations are introduced above, although they deserve a more
thorough description. The following property set contains two property declarations that
demonstrate the major features of property declarations:
property set Example2 is -- A single-valued property Stack_Size:
9/14/2006
78
inherit Size applies to (system, process, thread) => 1 KB; -- A multi-valued property Source_Files: list of aadlstring applies to (all); end Example2;
A property declaration gives a type for the property: the type may be given by
referencing a named type, or by giving the type specification in-line. The property
declaration for Stack_Size references the type AADL_Properties::Size2 while the
property declaration for Source_Files uses the type aadlstring directly. The
Source_Files property is a multi-valued property, one whose values are a list of strings.
For example the value ("file1.c", "file2.c") can be assigned to the property
Source_Files. In general, a property is made multi-valued by writing “list of” before its
type, and lists are denoted by comma-separated property value expressions enclosed in
parentheses.
The property declaration for Stack_Size uses the optional “inherit” modifier, which
affects how the property lookup algorithm looks for the values of this property. If a
property is “inherit,” and no property association for that property is found in the current
component, then the containing component is searched for a property association. This is
useful, for example, to allow all threads in a thread group to defer to the thread group if
they are all supposed to have the same property value.
All property declarations in addition to giving a type, must also have an “applies to”
clause. This clause specifies those categories of components in the specification for
which this property may be associated with a value. In addition to the standard
component categories, this list may specify that the property applies to mode, port
group, flow, [event] [data] port, server subprogram, parameter, and connections of
various kinds. The component categories may also be qualified by classifier references.
For example, a property that applies to (processor Intel_x86) may only be associated
with processor components whose component classifier the processor type Intel_x86 or
one of its descendents. The keyword “all” is used to indicate that the property applies to
all components.
Finally, a property declaration may optionally associate a default value with the property.
If the property lookup algorithm is unable to find a value associated with the property for
2 Normally property names must be qualified by their containing property set, but the AADL specification
allows the members of the property sets AADL_Properties and AADL_Project to be named without
qualification.
9/14/2006
79
a particular component then the default value is used. Otherwise, the property value is
considered to be “not present.”
5.2.3 Basic AADL Property Associations
A particular element of an AADL specification is given a particular value for a particular
property via a property association. Property associations are made with the properties
clause of component declarations, and within subcomponent declarations. In general,
property associations apply to the declarative AADL specification, and thus all instances
of a component implementation will have the same property values. The declarative
model can embody property associations for specific subcomponent instances via
contained property associations, which provide a path to the particular subcomponent or
feature to which the property applies. The specification below exemplifies the use of
property associations.
thread implementation MyThread.Impl properties Example2::Source_Files => ("MyThread.c", "Helper.c"); end MyThread.Impl; process implementation MyProcess.Impl subcomponents t1: thread MyThread.Impl; t2: thread MyThread.Impl; properties Example2::Stack_Size => 2 KB; end MyProcess.Impl; system implementation Main.Impl subcomponents p: process MyProcess.Impl { Example2::Stack_Size => 4 KB applies to t1; }; properties Example2::Source_files +=> ("Main.c"); end Main.Impl;
We have three component implementation declarations. The properties clause of
MyThread.Impl associates via the => operator the value ("MyThread.c", "Helper.c")
with the Source_Files property. The properties clause of Main.Impl, however, appends
via the +=> operator the value ("Main.c") to the Source_Files property. The full value
of the Source_Files property for Main.Impl is the value of Source_Files in the
component type Main (not shown) with the value ("Main.c") appended to it.
The properties clause of MyProcess.Impl associates the value 2 KB with the Stack_Size
property. Because this property is declared with the inherit modifier, the two thread
subcomponents will also have this property value for Stack_Size.
The contained property association on subcomponent p in Main.impl, however, changes
the value of the Stack_Size property for the specific thread instance t1 of the process
instance p when Main.Impl is instantiated. If instead the property association on p were
9/14/2006
80
{ Example2::Stack_Size => 4 KB; }, then the property association would refer to the
declarative model instead, changing the value of Stack_Size for the process
subcomponent itself.
Property associations can be more complicated when modes are used. Modal property
associations and other complicating issues are discussed in Section 5.7 “Advanced
Property Associations.”
5.2.4 The “SecurityLevel” Property
Our analysis relies on the assignment of security levels to components. There is no
standard property for specifying this, so we declare a new SecurityLevel property in a
new SEI property set:
property set SEI is SecurityLevel: aadlinteger applies to (data, subprogram, thread, thread group, process, memory, processor, bus, device, system); end SEI;
For our analysis, the security level of a component is an integer value. The property
applies to all categories of components that can make up a system, but not to connections
or to other model elements such as ports or modes.
Here is an example AADL specification that makes use of the new property:
thread Peter features pe: in event port; pd: out data port signal; properties SEI::SecurityLevel => 4; end Peter; thread implementation Peter.Default end Peter.Default; thread Pierre features pd: in data port signal; pe: out event port; properties SEI::SecurityLevel => 7; end Pierre; thread implementation Pierre.Default properties -- implementation overwrites the property value of the type SEI::SecurityLevel => 8; end Pierre.Default; process Proc end Proc; -- This component will have its SecurityLevel property value -- updated to be maximum of the subcomponent T1 and T2 values: 8 process implementation Proc.Impl subcomponents
9/14/2006
81
T1: thread Peter.Default; T2: thread Pierre.Default; connections -- Good connection: flow from level 4 to level 8 good: data port T1.pd -> T2.pd; -- Bad connection: flow from level 8 to level 4 bad: event port T2.pe -> T1.pe; properties -- Bad: Security Level isn't high enough SEI::SecurityLevel => 6; end Proc.Impl; system Main end Main; -- This component will receive a SecurityLevel property value -- to be the subcomponent value: 8 system implementation Main.Impl subcomponents p1: process Proc.Impl; end Main.Impl;
Thread types Peter and Pierre have SecurityLevel values of 4 and 7, respectively. The
Thread implementations Peter.Default and Pierre.Default have SecurityLevel values of
4 and 8 respectively. The analysis will issue a warning that the security level of
Proc.Impl is not high enough and that it has been upgraded, in this case from 6 to 8.
Analysis will also issue a warning that the security level of Main.Impl has been set to 8.
Process Proc.Impl has two connections between the two threads, one in each direction.
The connection from T1 to T2 is okay because subcomponent T1 has a security level of 4
which is less than T2’s security level of 8: data is traveling from a less secure to a more
secure component. But the connection from T2 to T1 will be flagged by the analysis as
allowing data to travel from a more secure to a less secure component. Figure 24 shows
the errors and warnings generated by the analysis plug-in for this example.
Figure 24: Results of applying security level analysis to the sample specification.
5.2.5 Property Lookup
Because property values can be inherited from ancestor types and as well as along the
component containment hierarchy, the property values associated with a particular
component may not all be declared in the component itself. In fact, because of the
append operator +=> for list values, the value itself may be constructed from property
associations declared in multiple components. The AADL Specification specifies the
9/14/2006
82
algorithm used to determine the property value associated with a particular property for a
particular component. The gist of the algorithm is as follows:
1. Search the component itself for an appropriate property association
2. Apply the lookup algorithm to the category of the component.
3. If the property is declared with the inherit modifier, apply the lookup algorithm
to the container of the component.
4. Use the default property value, if one exists.
5. Otherwise the property value is considered to be undefined.
An example lookup is illustrated in Figure 25. Instance4 is an element in the system
instance hierarchy. The value of one of its properties is determined by first looking for a
property associated with the instance itself—shown as step 1. This would be specified by
a contained property association. The contained property association for this instance
declared in a component implementation highest in the instance hierarchy determines that
value. If no instance value exists, the implementation (ImplA) of the instance is
examined (step 2). If it does not exist, ancestor implementations are examined (step 3).
If the property value still has not been determined, the component type is examined (step
4). If not found there, its ancestor component types are examined (step 5). If not found
and the property is inherited, for subcomponents and features, the enclosing
implementation is examined. Otherwise, the containing component in the component
instance hierarchy is examined (step 6). Finally, the default value is considered.
Figure 25: Example of the order in which model components are search for property associations. The model on the
left is an AADL instance model; the model on the right is an AADL declarative model.
The lookup process must also take into account modal properties, modal subcomponents,
property references, and the append operator. The interaction of modes with the property
lookup process together with the complexities of modal properties described above
necessitate the introduction of an additional level of abstraction in the property lookup
API provided by OSATE; see Section 5.8.5 “Getting Property Values.”
9/14/2006
83
5.3 AADL Properties in the Meta Model
Package edu.cmu.sei.aadl.model.properties contains the meta model classes related to
properties. Figure 26 shows the class PropertyHolder which is the super class for all
model classes representing AADL elements that can be associated with property values.
This class contains a single attribute “properties” that refers to the property associations
declared in that element (see Figure 27). This class also contains the methods for looking
up and setting property values. These methods are described in Section 5.7 “Advanced
Property Associations.”
Figure 26: The PropertyHolder class and its descendents.
Figure 27: Classes PropertyDeclaration and PropertyAssociation.
9/14/2006
85
Figure 29: Classes for representing Boolean property values. Also shown is the PropertyReference class.
A property declaration is represented by the PropertyDefinition class, shown in Figure
27. When writing a plug-in, you generally do not have to directly manipulate the
attributes of PropertyDefinitions; rather you simply need to obtain the
PropertyDefinition object for the property whose values you are interested in looking
up. Methods for retrieving specific PropertyDefinition objects are described below.
Also shown in Figure 27 is the PropertyAssociation class which models the assignment
of a particular value to a particular property for a particular component. You should
never have to directly manipulate PropertyAssociation objects when writing a plug-in.
The property value lookup methods, described in Section 5.8.5 “Getting Property
Values,” interpret these objects, and the property value setting methods, described in
Section 5.8.6 “Modifying Property Associations,” change their values or create new
instances as necessary.
AADL property expressions are represented using PropertyValue objects. In most
cases, a PropertyValue object will not point to an elaborate structure; see Figure 28.
AADL, however, does allow Boolean arithmetic, and BooleanValue object can be part of
a tree describing a Boolean predicate; see Figure 29. AADL also allows a property value
9/14/2006
86
to be a reference to the value of another property or to a property constant, which adds
some complexity to the model: consider the BooleanOrPropertyReference,
NumberOrPropertyReference, PropertyReference, and ReferencedProperty classes.
If you are only interested in retrieving property values, you can avoid the complexity of
property expressions because the property lookup process also takes care of evaluating
property references and Boolean expressions. When creating new property associations
via the property setting methods, however, you must provide new PropertyValue objects
to be attached to the meta model. A tree containing BooleanValue or
PropertyReference objects could be created for this purpose. It is the responsibility of
the creator of these objects to make sure that they result in legal AADL property
expressions.
In general, when retrieving property values in a plug-in you know which property you are
interested in, and therefore, the PropertyType of the property, and the specific subclass
of PropertyValue that its values will be.
5.3.1 Properties and the Instance Model
A PropertyAssociation is considered to be a contained property association if it has a
non-empty “appliesTo” attribute. OSATE’s property-related methods ignore such
PropertyAssociation objects when invoked on components making up the declarative
model because they declare information relevant to the instance model only. These
property associations are interpreted when a system instance is instantiated into an
instance model. During this process, the contents of the “appliesTo” attribute are used to
identify the particular InstanceObject that represents the instance component to which
the property association applies. A new PropertyAssociation object is then attached to
that object’s “properties” attribute describing the property association.
The “derived” attribute of PropertyAssociation is only meaningful when the
PropertyAssociation is part of an instance model. It indicates that the property
association is derived from a property association in the declarative model. These
property associations are redundant, because they duplicate associations that the property
lookup algorithm would find by deferring to the declarative model (see Section 5.2.5
“Property Lookup”). But by being made explicit in the instance model they short-circuit
the lookup process and remove the need for examining the declarative model. This is
useful because OSATE does not load a model until it is actually used, and thus by
copying all the property associations into the instance model we can in many cases
prevent the declarative model from being loaded during an analysis of the instance
9/14/2006
87
model. By default, the system instantiation process used by OSATE “caches” the values
of all properties explicitly used in the declarative model.
There are two special cases in the instance model representation relating to properties:
1. When representing reference values in the instance model, the class
edu.cmu.sei.aadl.model.instance.InstanceReferenceValue is used instead of its
more generic super class ReferenceValue. This is because in declarative models
only a component path that represents a notional component instance can be
provided, but in an instance model, a reference to the actual component instance
can be provided. Specifically, the InstanceReferenceValue has an attribute
“referencedInstanceObject” that points to an InstanceObject instance.
The property lookup process takes care of translating ReferenceValues into
InstanceReferenceValues as needed. When writing an analysis, this distinction
must be kept in mind depending on whether the analysis operates over a
declarative or instance model.
2. The “in modes” attribute of PropertyAssociations in an instance model refers to
SystemOperationMode objects instead of Mode objects. These objects are
described in more detail in the section on system operation modes. Again, the
property lookup and model instantiation processes takes care of making this
translation, but this distinction is reflected in what kind of objects are expected
when looking up or setting modal properties values; see Sections 5.8.5 “Getting
Property Values” and 5.8.6 “Modifying Property Associations.”
5.4 Implementing the Security Level Plug-in
Here we complete the description of the security level plug-in and use it to introduce the
following OSATE API capabilities, which are more fully described in subsequent
sections:
• How to look up a property value.
• How to manipulate a number value.
• How create a new number value.
• How to set a property value.
The security level analysis runs in two passes:
1. The first pass checks both that subcomponents are contained in more secure
components and infers missing security levels.
9/14/2006
88
2. The second pass checks that connections flow from lower level to higher level
components.
We need two passes because we cannot check connections until we are sure that all
components have a security level associated with them. We must, therefore, visit all the
components first to make sure that any inferred property values have “bubbled” all the
way up the component containment hierarchy. We implement each pass as a separate
subclass of AadlProcessingSwitch.
5.4.1 Getting the Property Declaration and Driving the Analysis
The CheckSecurity class, our Eclipse action class for driving the analysis, is shown
below. The class demonstrates how to initialize static references to property definitions
once at the beginning of an analysis. This avoids having to find the property definition
every time it is needed, which in this case would be every time a component is visited by
the analysis. Class AaxlReadOnlyAction (superclass of AaxlModifyAction, which our
action extends) declares the method initPropertyReferences(). This method is called
before doAaxlAction is called. The default implementation does nothing; actions that
use properties, however, should override this method to initialize references to any
property definitions, types, and constants used by the analysis. The recommended pattern
is for references to these elements to be public static volatile3 fields of the action class.
That way they can be easily referenced from instances of the model traversal classes and
other helper classes.
Property definitions, types, and constants are looked up using the methods
AaxlReadOnlyAction.lookupPropertyDefinition,
AaxlReadOnlyAction.lookupPropertyType, and
AaxlReadOnlyAction.lookupPropertyConstant which are summarized in the table
below. If the definition is not found, these methods return null and also update an
internal list of unfound definitions. After initPropertyReferences returns, if any of the
items are not found, then instead of calling doAaxlAction, a dialog box is presented to
the user listing those elements that were not found; see Figure 30 for an example. More
information about these methods is in Section 5.8.2 “More about
AaxlReadOnlyAction.initPropertyReferences”.
Operation Method
Look up a property in the named PropertyDefinition lookupPropertyDefinition(
3 By making the field volatile we insure that users of the field will always see the most up-to-date value,
and thus won’t see a field value from a previous run of the analysis.
9/14/2006
89
property set String propertySet, String name)
Look up a property type in the named
property set PropertyType lookupPropertyType(
String propertySet, String name)
Look up a property constant in the
named property set PropertyConstant lookupPropertyConstant(
String propertySet, String name)
Figure 30: Example error dialog reporting that property set elements needed by a plug-in could not be found.
Our security level analysis is implemented as an AaxlModifyAction, because it may
modify the model by inserting inferred property values. It uses the default error handling
mechanism because it has no other preconditions to check. The action uses two different
model traversal classes, one for each pass described above. For the first pass, analysis
invokes the processBottomUpComponentImpl method, which visits the components in
an order that insures that a component is visited before any of the components that
reference it are. For the second pass, a normal pre-order traversal is sufficient. We pass
the action’s MarkerReporter to each traversal instance so that they can report warnings
and errors as they are found.
public class CheckSecurity extends AaxlModifyAction { private static final String SECURITYLEVEL = "SecurityLevel"; private static final String SEI_PACKAGE = "SEI"; public static volatile PropertyDefinition securityLevel = null; protected void initPropertyReferences() { // Initialize our one property reference securityLevel = lookupPropertyDefinition(SEI_PACKAGE, SECURITYLEVEL); } public void doAaxlAction(AObject obj) { if (obj == null) return; final AObject as = obj.getAObjectRoot(); /* Ensure that enclosing component security level encompasses * contained security levels. */ if (as instanceof AadlSpec) { final ComponentSecuritySwitch componentSecuritySwitch = new ComponentSecuritySwitch(getMarkerReporter());
9/14/2006
90
// Walk up the component implementation reference hierarchy componentSecuritySwitch.processBottomUpComponentImpl( (AadlSpec) as); // Check security along connections final ConnectionSecuritySwitch connectionSecuritySwitch = new ConnectionSecuritySwitch(getMarkerReporter()); connectionSecuritySwitch.processPreOrderAll(as); } } }
5.4.2 Class ComponentSecuritySwitch
Checking the security levels of the declarative components is a straightforward task: get
the security level of the component and compare it against the security levels of its
subcomponents. Because we are also interested in being able to correct the security level
of the components, we actually first find the maximum security level of the
subcomponents, and then compare that value against the component’s value. If the
component’s value is non-existent or less than the maximum subcomponent value, then
we upgrade the component’s SecurityLevel property association.
To get the property values we use the method
PropertyHolder.getSimplePropertyValue(PropertyDefinition), which is a
convenience method for getting a property value that is not expected to be modal and is
not list-valued. The method returns a PropertyValue object, or null if the property value
is undefined, is a list, or depends on modes. We reference the property declaration of the
SecurityLevel property using the previously initialized static reference
CheckSecurity.securityLevel. Once we have the property value, we check that it is an
IntegerValue, which also checks that the value is non-null, and get the value as a long
by casting the object back to an IntegerValue and invoking getValue().
When the security level of the component must be set, either because no value was found
or because the value is not high enough, we create a new IntegerValue object, set its
value, and then set the property value. We always create a new PropertyValue object
rather than modifying the object obtained from looking up the property value, because we
do not know from where in the model—if at all—the property value object comes, and
modifying it directly may have unintended consequences; see Section 5.5 “Getting
Simple Property Values” for more information. We set the value of the IntegerValue
object using the method setNewValue(long), which makes sure the value’s numeric and
string representations are consistent; see Section 5.6.6 “Setting Number Values.” Finally,
we associate the new value with the property for the component using
PropertyHolder.setPropertyValue(PropertyDefinition, PropertyValue). This method
9/14/2006
91
is one of several property setting methods described in more detail in Section 5.8.6.1
“Setting Property Associations.”
public class ComponentSecuritySwitch extends AadlProcessingSwitch { public ComponentSecuritySwitch(final MarkerReporter reporter) { super(reporter); } protected final void initSwitches() { componentSwitch = new ComponentSwitch() { public Object caseComponentImpl(ComponentImpl ci) { // Get my security level, if declared final PropertyValue cipv = ci.getSimplePropertyValue(CheckSecurity.securityLevel); long cilv = 0; if (cipv instanceof IntegerValue) { cilv = ((IntegerValue) cipv).getValue(); } // Get the max security level of my subcomponents long maxslv = 0; final EList subs = ci.getXAllSubcomponent(); for (Iterator it = subs.iterator(); it.hasNext();) { final Subcomponent sub = (Subcomponent) it.next(); final ComponentImpl sci = sub.getComponentImpl(); if (sci != null) { PropertyValue scipv = sci.getSimplePropertyValue(CheckSecurity.securityLevel); if (scipv instanceof IntegerValue) { long slv = ((IntegerValue) scipv).getValue(); // Update max subcomponent security level if (slv > maxslv) maxslv = slv; } } } if (maxslv > cilv) { /* Subcomponents have higher security level than me. * Update my declared security level. */ if (cipv != null) { // My declared level is wrong reportWarning(ci, "Security level updated from " + cilv + " to the maximum of the subcomponent values: " + maxslv); } else { // Didn't have a declared level reportWarning(ci, "Security level set to the maximum of the " + "subcomponent values: " + maxslv); } // Create new property value: An Integer value final IntegerValue newpv = PropertyFactory.eINSTANCE.createIntegerValue(); // Set to max security level newpv.setNewValue(maxslv); // Set the property association ci.setPropertyValue(CheckSecurity.securityLevel, newpv); } return DONE; } };
9/14/2006
92
} }
5.4.3 Class ConnectionSecuritySwitch
To check a connection we need the security levels of the connections end points. These
are retrieved from the source and destination context components of the connections.
The methods Connection.getAllSrcContextComponent() and
Connection.getAllDestContextComponent() get the Subcomponent or
ComponentImpl that is the source or destination of the connection. It is not sufficient to
use the Connection.getXAllSrc() and Connection.getXAllDest() methods, because
when the connection is made through a port group, the latter pair of methods return the
port group features that participate in the connection, whereas the former pair of methods
search beyond the port group to find the component that contains the port group.
Once we have the end points of the connection, we get the property value associated with
SecurityLevel as described above, and compare the level of the source component
against the level of the destination component.
public class ConnectionSecuritySwitch extends AadlProcessingSwitch { public ConnectionSecuritySwitch(final MarkerReporter reporter) { super(reporter); } protected final void initSwitches() { connectionSwitch = new ConnectionSwitch() { public Object caseConnection(final Connection conn) { // Ignore access connections if (conn instanceof DataAccessConnection || conn instanceof BusAccessConnection) { return DONE; } // Get the connection contexts final PropertyHolder scxt = conn.getAllSrcContextComponent(); final PropertyHolder dcxt = conn.getAllDstContextComponent(); if (scxt == null || dcxt == null) return DONE; // Get the security levels of the end points final PropertyValue spv = scxt.getSimplePropertyValue(CheckSecurity.securityLevel); final PropertyValue dpv = dcxt.getSimplePropertyValue(CheckSecurity.securityLevel); long slv = 0; if (spv instanceof IntegerValue) { slv = ((IntegerValue) spv).getValue(); } long dlv = 0; if (dpv instanceof IntegerValue) { dlv = ((IntegerValue) dpv).getValue(); } // Error if source level is higher than the dest level if (slv > dlv) { reportError(conn,
9/14/2006
93
"Security level violation: Source has level " + slv + " and destination has level " + dlv); } return DONE; } }; } }
5.5 Getting Simple Property Values
A plug-in typically needs to get the values from specific properties, and thus the author of
the plug-in knows ahead of time the property type of the property, whether the property’s
values should be lists, and whether the value should depend on the mode. Section 5.8.5
“Getting Property Values” describes the general property retrieval methods, but OSATE
provides many other, easier-to-use methods that take advantage of this prior knowledge.
Section 5.4.1 “Getting the Property Declaration and Driving the Analysis” introduces the
method PropertyHolder.getSimplePropertyValue which gets a non-list property value
whose value does not depend upon modes. There are three versions of this method:
1. getSimplePropertyValue(PropertyDefinition pd) returns a PropertyValue
object, or null if the property value is not present, is a list, or depends on modes.
2. getSimplePropertyValue(String name) looks up the property value of the
named predeclared property. That is, the property definition of the given name is
searched for in the Aadl_Properties and Aadl_Project property sets. An
IllegalArgumentException is thrown if the named property cannot be found.
Otherwise, returns a PropertyValue object, or null if the property value is not
present, is a list, or depends on modes.
3. getSimplePropertyValue(String propertySet, String name) looks up the
property value of the named property. The named property is searched for in the
named property set. An IllegalArgumentException is thrown if the named
property cannot be found. Otherwise, returns a PropertyValue object, or null if
the property value is not present, is a list, or depends on modes.
A non-modal list-valued property value can be retrieved using the method
PropertyHolder.getPropertyValueList(PropertyDefinition) which returns a
java.util.List of PropertyValue objects, or null if the property value is not present or
depends on modes.
Method PropertyHolder.isModalPropertyValue(PropertyDefinition pd) can be used
to see if a particular property value depends on modes.
9/14/2006
94
While these methods make it easy to get a property value without worrying about modes,
they still require the programmer to cast the returned PropertyValue back to expected
property type. The class PropertyUtils in package edu.cmu.sei.aadl.model.properties
addresses this problem with a suite static helper methods that return a particular type of
property value, and perform common manipulations to the returned value. As above, all
the methods assume the property value is non-list and non-modal. Those that can, return
null in these cases; those that cannot return null because they do not return an object type
return a caller-provided default value. If the retrieved property value is not of the expect
type, the methods throw a ClassCastException. Those that take UnitLiterals throw an
IllegalArgumentException if the literal is not from the type of the given property. The
methods in PropertyUtils are shown in the following table.
Operation Method
Get a Boolean property
value boolean getBooleanValue(PropertyHolder ph,
PropertyDefinition pd, boolean defaultVal)
Get an enumeration property
value EnumLiteral getEnumLiteral(PropertyHolder ph,
PropertyDefinition pd)
Get a string property value String getStringValue(PropertyHolder ph,
PropertyDefinition pd)
Get an unscaled integer
value4 long getIntegerValue(PropertyHolder ph,
PropertyHolder pd, long defaultVal)
Get an unscaled real value4 double getRealValue(PropertyHolder ph,
PropertyHolder pd, double defaultVal)
Get a number value scaled
to given unit. double getScaledNumberValue(PropertyHolder ph,
PropertyDefinition pd, UnitLiteral unit,
double defaultVal)
Get the lower bound of a
range value scaled to a
given unit
double getScaledRangeMinimum(PropertyHolder ph,
PropertyDefinition pd, UnitLiteral unit,
double defaultVal)
Get the upper bound of a
range value scaled to a
given unit
double getScaledRangeMaximum(PropertyHolder ph,
PropertyDefinition pd, UnitLiteral unit,
double defaultVal)
Get the delta of a range
value scaled to a given unit double getScaledRangeDelta(PropertyHolder ph,
PropertyDefinition pd, UnitLiteral unit,
double defaultVal)
Get the instantiated
component referenced by a
reference value5
ComponentInstance
getComponentInstanceReference(InstanceObject io,
PropertyDefinition pd)
4 This method is intended for use on values that do not have associated units. If used on a value that does
have a unit, the value is returned, but the unit is lost, and thus it becomes difficult to interpret the result.
9/14/2006
95
5.6 Manipulating Property Values
This section describes some specific issues in the use of PropertyValue objects,
particularly in the use of IntegerValue and RealValue objects.
The attributes of PropertyValue objects can be changed using the attribute setter
methods. Changing the values of the PropertyValue objects obtained from the property
lookup methods, however, may not have the intended affects on the model. Because the
property lookup methods handle searching the component hierarchies, interpreting
references to property constants, interpreting references to other property values, and
evaluating Boolean expressions, the PropertyValue objects obtained from the lookup
may be located in surprising locations in the model, and it is possible they may be freshly
created objects and not located in the model at all. To change the value of a property it is
best to create a new PropertyValue object to use with setPropertyValue. For example,
the following code segment increments an integer property value associated with a
particular component:
final IntegerValue iv = (IntegerValue) ph.getPropertyValue(pd); if (iv != null) { IntegerValue iv2 = PropertyFactory.eINSTANCE.createIntegerValue(); iv2.setNewValue(iv.getValue() + 1); ph.setPropertyValue(pd, iv2);
(We assume pd refers to a property definition of type aadlinteger.)
5.6.1 Copying PropertyValues
Sometimes you want to copy a property value from one property association to another.
You might be tempted to use the property value objects returned by a property lookup
method and feed them back to setPropertyValue, as shown below:
// Anti-pattern for copying property values final List val = ph.getPropertyValueList(pd_propA); // Do not do this! ph.setPropertyValue(pd_propB, val);
Do not do this. This can have unexpected effects on the model because it can cause a
PropertyValue object to have a new containing object in the meta model, and thus
destroy the original property association. Instead, you should create a copy of the
property value objects and set the new the property value using the copies:
// Pattern for copying property values final List val = ph.getPropertyValueList(pd_propA); // Do this instead
5 Unlike the other methods, this method operates on an InstanceObject instead of a PropertyHolder
because it only makes sense to use it on a member of an instance model. In general, a reference value can
refer to an InstanceObject, but this method reflects the more common case; a ClassCastException is
thrown if the reference value does not refer to a ComponentInstance.
9/14/2006
96
final List valCopy = AadlUtil.copyList(val); ph.setPropertyValue(pd_propB, valCopy);
The static method AadlUtil.copyList(List) takes a List of EObject references and
returns a new List object whose contents are copies of the objects in the original list, in
the same order. Any references shared among the objects in the list are also shared
among objects in the copied list. The copying is performed using the method
EcoreUtil.copy(EObject), which deep-copies an individual model object. These
copying methods are useful for copying model structure generally, but we cover them
here because we have found them most useful when manipulating property values.
Also, IntegerValue and RealValue (via the superclass NumberValue) contain the
methods cloneNumber() and cloneAndInvert(). The first method returns a copy of the
number. The second returns a copy that has the inverse value.
5.6.2 Unparsing Property Values
To get the string representation of a property value, use the method
PropertyValue.getValueAsString().
5.6.3 Using Range Values
The AADL specification allows the minimum, maximum, and delta components of the
range to be specified using either literals or references to property constants. Thus, in the
meta model, the “minimum,” “maximum,” and “delta” attributes of RangeValue contain
NumberOrPropertyReference objects. You can get the value of a
NumberOrPropertyReference object using getNumberValue(). We have added three
convenience methods to RangeValue to provide direct access to the numeric values of its
attributes: getMinimumValue(), getMaximumValue(), and getDeltaValue(). All three
methods return a NumberValue.
5.6.4 Getting Type Literals
Given a UnitsType object, the member UnitLiteral objects can be retrieved by name
using the method UnitsType.findUnitLiteral(String unitName). If no literal with the
given name exists the method returns null.
Similarly, the method EnumType.findEnumLiteral(String litName) looks for the
named enumeration literal in the given enumeration type, and returns null if the literal is
not found.
9/14/2006
97
5.6.5 Scaling Number Values
As described in Section 5.2.1 “AADL Property Types,” aadlreal and aadlinteger
property types can specify that their values have units. In the meta model, this is
captured by the “unitLiteral” attribute of NumberValue. However, the “value” attribute
of RealValue and IntegerValue is maintained separately from “unitLiteral.” It is thus
the case that interpreting the actual value represented by a RealValue or IntegerValue
involves checking the values of two attributes, as well as interpreting the value of the unit
literal itself relative to the other unit literals in its UnitType.
OSATE shields the plug-in programmer from this tedious process via the methods
NumberValue.getScaledValue() and NumberValue.getScaledValue(UnitLiteral).
Both methods return a double value: the first returns the value scaled relative to the base
unit of the number’s UnitsType; the second method returns the value scaled relative to
the given UnitLiteral, which must be from the number’s UnitsType.
For example, consider the IntegerValue representing the AADL property expression 30
foot of type Example::Length. Method getScaledValue() returns 360.0, the value
scaled to the base unit inch. Invoking the parameterized method with the UnitLiteral
object representing the unit yard returns 10.0. Thus, given a PropertyHolder object ph
representing a component whose Example::Documentation_Thickness property has
value 30 foot, executing the following segment of code
final UnitsType units = (UnitsType) OsateResourceManager.findPropertyType( "Example", "English_Units"); final IntegerValue iv = (IntegerValue) ph.getSimplePropertyValue( "Example", "Documentation_Thickness"); System.out.println("Scaled Value: " + iv.getScaledValue()); System.out.println("In Yards: " + iv.getScaledValue(units.findUnitLiteral("yard")));
results in the following console output:
Scaled Value: 360.0 In Yards: 10.0
5.6.6 Setting Number Values
The class NumberValue contains the attribute “valueString” which shadows the value of
the “value” attribute of RealValue and IntegerValue. This attribute is maintained so
that the number value can be unparsed to the same syntactic form from which it was
parsed. This is important because AADL allows integer values to be denoted in bases
other than ten, allows exponential notation for real values, and allows underscores to be
9/14/2006
98
inserted between numerals. These syntactic features are often important to the readability
of specifications, and thus it is separately maintained in the “valueString” attribute.
As a consequence, when the “value” attribute of a NumberValue is changed, the
“valueString” attribute should also be. Because it is inconvenient, and error prone, to
expect that setValueString be invoked every time setValue is invoked, NumberValue
also features the method setNewValue(Number) which simultaneously updates both the
“value” and “valueString” attributes. Class RealValue has the more specific method
setNewValue(double), and class IntegerValue has the more specific method
setNewValue(long). Because integer values may be denoted in bases other than ten,
IntegerValue also has the method setNewValue(long value, int base), which allows the
base that the string representation should be in to be specified. If the base is not a value
between two and sixteen inclusive, base ten is used.
We do not offer any methods for controlling how a real value is represented as a string;
the setValueString method can be used in conjunction with the
java.text.DecimalFormat class to exercise finer control over the unparsing of
RealValue objects.
The unit literal for a number value, if one is desired, is set by the setUnitLiteral method.
As an example, executing the code segment
final UnitsType units = (UnitsType) OsateResourceManager.findPropertyType( "Example", "English_Units"); final IntegerValue iv2 = PropertyFactory.eINSTANCE.createIntegerValue(); iv2.setNewValue(18L); iv2.setUnitLiteral(units.findUnitLiteral("inch")); System.out.println("New value: " + iv2.getValueAsString()); System.out.println("valueString: " + iv2.getValueString()); System.out.println("Scaled Value: " + iv2.getScaledValue()); System.out.println("In Feet: " + iv2.getScaledValue(units.findUnitLiteral("foot")));
results in the following console output.
New value: 18 inch valueString: 18 Scaled Value: 18.0 In Feet: 1.5
5.7 Advanced Property Associations
Here we revisit the AADL specification and describe the advanced features of property
associations and how they affect property values. These features motivate the more
complicated aspects of the OSATE property value API discussed next.
9/14/2006
99
5.7.1 Modal Property Associations
A property may be associated with a particular value for a subset of a component’s
modes. This is specified by adding an “in modes” clause to the property association. An
“in modes” clause names one or more modes of the surrounding component
implementation declaration for which the property association applies. A properties
clause or a subcomponent properties clause may have more than one property association
for a particular property if the property associations have non-intersecting lists of modes.
When a property has both a modal and a non-modal property association, the non-modal
association is considered to apply for those modes not explicitly named in a modal
association.
The value associated with a property for a component may be affected by the modes of
components other than the component it is associated with. Consider the following
AADL specification, for example:
system implementation Inner.Impl modes InnerMode1: initial mode; InnerMode2: mode; properties PS::x => 1 in modes (InnerMode1); PS::x => 2 in modes (InnerMode2); end Inner.Impl; system implementation Outer.Impl subcomponents sub: system Inner.Impl { PS::y => 3 in modes (OuterMode1); PS::y => 4 in modes (OuterMode2); }; modes OuterMode1: initial mode; OuterMode2: mode; end Outer.Impl; system Main.Impl subcomponents sub: system S.I; ... modes: M1: initial mode; M2: mode; properties PS::z => 5 applies to sub.a.b.c.d in modes (M1); end Main.Impl;
For component implementation Inner.Impl, the value associated with property PS::x
depends on the mode of the component itself. But the property value associated with
PS::y of subcomponent sub of Outer.Impl depends on the mode of the Outer.Impl
component implementation. When Main.Impl is instantiated, the contained property
association in Main.Impl makes the value of PS::z of a component instance five levels
down the containment hierarchy depend on the mode of the root system component.
9/14/2006
100
5.7.2 Nonexistent Property Values
The value associated with a property may also depend on the modes of the resulting
system because subcomponents can be declared to exist in certain modes only. If a
component does not exist in a particular mode, then it does not make sense to look up the
values associated with properties for that component. The value, in such cases, is said to
be nonexistent. The modes in which a component exists can interact with the modes of
its property associations, as shown in the following example:
system implementation ModalSubcomponents.Impl subcomponents sub1: system S1.Impl { PS::x => 0; } in modes (M1, M2); sub2: system S2.Impl { PS::x => 1 in modes (M1); } in modes (M1, M3); sub3: system S3.Impl { PS::x => 2 in modes (M2); PS::x => 3 in modes (M3); } in modes (M2, M3); modes M1: initial mode; M2: mode; M3: mode; end ModalSubcomponents.Impl;
Here, property PS::x of subcomponent sub1 effectively has a modal property association
because sub1 only exists in modes M1 and M2. In particular, for sub1, the value of
PS::x is nonexistent in mode M3. Similarly, the property value of PS::x is nonexistent
for subcomponent sub2 in mode M2, and for subcomponent sub3 in mode M1. The
following table summarizes the value associated with property PS::x for the three
subcomponents across the modes of ModalSubcomponents.Impl:
Mode Subcomponent sub1 Subcomponent sub2 Subcomponent sub3
M1 0 1 Nonexistent
M2 0 Nonexistent 2
M3 Nonexistent Not Present6 3
5.7.3 Modes and Property References
The value associated with a property may also depend on the modes of the system
because the value references the values of other properties that are modal. This is shown
in the following example:
property set PS is bool1: aadlboolean => true applies to (system); bool2: aadlboolean => false applies to (system); bool3: aadlboolean applies to (system); end PS;
6 Assuming that property PS::x does not have a default value.
9/14/2006
101
system Example properties PS::bool3 => value(PS::bool1) and value(PS::bool2); end Example; system implementation Example.Impl modes M1: initial mode; M2: mode; properties PS::bool1 => false in modes (M1); PS::bool2 => true in modes (M2); end Example.Impl;
For system type Example, the value associated with property PS::bool3 is false: this
value is the result of evaluating the property expression “value(PS::bool1) and
value(PS::bool2).” To evaluate the expression, the values associated with PS::bool1
and PS::bool2 for Example are used: true and false, respectively. The property
association is not modal, and in fact cannot be because modes do not apply to component
types.
The system implementation Example.Impl associates new values with properties
PS::bool1 and PS::bool2, but only in modes M1 and M2, respectively. The value
associated with PS::bool3 for Example.Impl thus depends on the mode of the
component because it depends on the values of PS::bool1 and PS::bool2:
Mode PS::bool1 PS::bool2 PS::bool3
M1 false false false
M2 true true true
5.8 OSATE Properties API
This section describes the OSATE API for manipulating properties in AADL models.
The methods for getting property declarations, looking up property values, and setting
property values are described.
5.8.1 Using Predeclared Properties
The class PredeclaredPropertyNames in package
edu.cmu.sei.aadl.model.property.predeclared contains static references to names of
the property definitions, types, and constants declared in the standard AADL property
sets AADL_Properties and AADL_Project. [Doesn’t currently contain all of them, only the
ones we have needed. Should fix this.] When looking up property names in the
initPropertyReferences() method of your plug-in action, you should use these constants
to get references to predeclared types, constants, and properties.
9/14/2006
102
5.8.2 More about AaxlReadOnlyAction.initPropertyReferences
The method AaxlReadOnlyAction.initPropertyReferences and the property look up
methods are introduced in Section 5.4.1 “Getting the Property Declaration and Driving
the Analysis”. Here we discuss additional details about initializing property references.
The complete set of property look up methods defined in AaxlReadOnlyAction is given
in the table below. There are three versions of each property definition, property type,
and property constant look up method. Previously described are the methods
lookupPropertyDefinition(String, String), lookupPropertyType(String, String), and
lookupPropertyConstant(String, String) that look for the named item in the named
property set. If the item is not found the method returns null and adds the item to the
action’s list of “unfound” properties. There are also single parameter versions that look
for the named item in the predeclared property sets Aadl_Properties and Aadl_Project.
The methods lookupOptionalPropertyDefinition, lookupOptionalPropertyType, and
lookupOptionalPropertyConstant return the definition, or null if not found, but do not
update the list of unfound definitions. It is assumed the plug-in is written to function
correctly when an optional definition is absent.
Operation Method
Look up a predeclared property, i.e.,
one declared in Aadl_Properties or
Aadl_Project
PropertyDefinition lookupPropertyDefinition(
String name)
Look up a property in the named
property set PropertyDefinition lookupPropertyDefinition(
String propertySet, String name)
Lookup an optional property in the
named property set PropertyDefinition
lookupOptionalPropertyDefinition(
String propertySet, String name)
Look up a predeclared property type PropertyType lookupPropertyType(
String name)
Look up a property type in the named
property set PropertyType lookupPropertyType(
String propertySet, String name)
Look up an optional property type in
the named property set PropertyType lookupOptionalPropertyType(
String propertySet, String name)
Look up a predeclared property
constant PropertyConstant lookupPropertyConstant(
String name)
Look up a property constant in the
named property set PropertyConstant lookupPropertyConstant(
String propertySet, String name)
Look up an optional property
constant in the named property set PropertyConstant
lookupOptionalPropertyConstant(
String propertySet, String name)
9/14/2006
103
If your plug-in has other preconditions that it checks before performing its analysis, and
you want to report all the errors together, the default error reporting can be suppressed by
overriding the method AadlReadOnlyAction.suppressErrorMessages() so that it
returns true. In this case, doAaxlAction will always be called, and it is your
responsibility to check whether there were any errors in initPropertyReferences and to
react appropriately. You can check for errors using the method
hasPropertyLookupErrors(). You can get a list of the property set elements that were
not found by calling getPropertyLookupErrors(), which returns a List of Strings
identifying those elements that were not found. The strings are of the form "property
definition propertySet::name", "property type propertySet::name", and "property
constant propertySet::name" as appropriate.
5.8.3 General Lookup of Property Sets, Definitions, Constants, and Types
As discussed in Section 5.3 “AADL Properties in the Meta Model,” AADL property
name declarations are represented as PropertyDefinition objects, which are contained in
PropertySet objects. Given a PropertySet object, a property definition can be looked
up using the method PropertySet.findPropertyDefinition(String name), which returns
the PropertyDeclaration object if it exists, or null if it does not. Similarly, PropertySet
also contains the methods findPropertyType(String name) and
findPropertyConstant(String name).
But how is a PropertySet object retrieved? The class OsateResourceManager in
package edu.cmu.sei.aadl.model.pluginsupport manages the AADL models, packages,
and property sets loaded into Eclipse. In effect, it is the root of the AADL name space. It
contains static methods to lookup property sets, which are summarized in the table below.
Operation Method
Lookup the named property set or null if
not found PropertySet findPropertySet(String ps,
AadlSpec context)
Get all the globally defined propertysets Set getAllPropertySets()
Get all the property sets available in the
given context Set getAllPropertySets(AadlSpec context)
Property set lookup depends on a context, which requires further explanation. OSATE
prefers that property sets be declared separately from AADL specifications, one property
set per file. These files are stored in a distinguished directory, propertysets, in an
9/14/2006
104
Eclipse/OSATE AADL project. These property sets are called global property sets and
can be referenced by any AADL specification in the workspace. But to be compatible
with older versions of OSATE, property sets may also be declared in the same file as an
AADL specification. Such property sets are called local property sets and they may only
be referenced by component specifications contained in the same file, or by instance
models generated from system implementations declared within the same file. In
addition, they shadow any global property set with the same name. Thus, when looking
up a property set we need to first search locally and then globally. But we need to know
in which AADL specification we should search for local property sets. The context
parameter provides this information; if null, it means not to search for the property set
locally.
Thus the method findPropertySet first searches for the named property set in the given
AADL specification if it is non-null. Then it searches for the property set globally. If the
property set is not found the method returns null. The method getAllPropertySets()
returns a Set of PropertySet objects, one for each globally defined property set.
Similarly, the method getAllPropertySets(AadlSpec) returns all the property sets
available in the given context, including any local ones.
5.8.3.1 Getting the Context
The context for an object in a declarative model is the AadlSpec object that contains that
object. For an object in an instance model it is the the AadlSpec object that contains the
system implementation classifier that was instantiated to create the instance model.
Getting the context is encapsulated in the method
AObject.getPropertySetNameSpace(). This method returns null if the AadlSpec that is
the context does not in fact contain any property set declarations—this forces the
property set look up method findPropertySet to search for the property set globally.
The lookup methods in AaxlReadOnlyAction do not require a context parameter
because AaxlReadOnlyAction determines the context from the model element that was
selected when the action was invoked.
5.8.3.2 Additional Property Lookup Methods
The class OsateResourceManager also contains static convenience methods that
combine findPropertySet with one of PropertySet.findPropertyDeclaration,
PropertySet.findPropertyType, and PropertySet.findPropertyConstant. These
methods return null if the property set is not found, or if the given element is not found
within the property set. The methods are summarized in the table below.
9/14/2006
105
Operation Method
Find a predeclared property
constant PropertyConstant findPropertyConstant(
String name, AadlSpec context)
Find a property constant in the
named property set PropertyConstant findPropertyConstant(
String psName, String name, AadlSpec context)
Find a predeclared property
definition PropertyDefinition findPropertyDefinition(
String name, AadlSpec context)
Find a property definition in the
named property set PropertyDefinition findPropertyDefinition(
String psName, String name, AadlSpec context)
Find a predeclared property type PropertyType findPropertyType(String name,
AadlSpec context)
Find a property type in the named
property set. PropertyType findPropertyType(String
psName, String name, AadlSpec context)
Class AadlUtil in package edu.cmu.sei.aadl.model.util contains some static methods for
getting “all” property definitions:
Operation Method
Get all the property definitions declared in
local property sets in the given context EList getAllLocalPropertyDefinition(
AadlSpec context)
Get all the property definitions declared in
global property sets EList getAllProperytDefinition()
Get all the property definitions—local and
global—declared in the given context EList getAllPropertyDefinition(
AadlSpec context)
5.8.4 Testing “Applies to”
It is sometimes interesting to know whether a particular property “applies to” a given
PropertyHolder. The method PropertyHolder.acceptsProperty(PropertyDefinition
pd) returns true if the property can be applied to the given component, that is, if the
component can hold property values associated with the given property.
5.8.5 Getting Property Values
Class PropertyHolder contains a small army of methods supporting the retrieval of
property values. The AADL property lookup algorithm is embodied in the method
PropertyHolder.getPropertyValue(PropertyDefinition pd) which returns the given
component’s property value for the given property. This method returns a
ModalPropertyValue object which deals with the most general case where a value of a
property association could depend on the modes of the components in the system. This
class is described in Section 5.8.5.1 “Modal Property Lookup.”
9/14/2006
106
A plug-in typically needs to get the values from specific properties, and thus the author of
the plug-in knows ahead of time the property type of the property, whether the property’s
values should be lists, and whether the value should depend on the mode. Section 5.5
“Getting Simple Property Values” introduces the PropertyHolder convenience methods
getSimplePropertyValue and getSimplePropertyValueList, as well as the methods of
the PropertyUtils class.
As already stated in Section 5.3 “AADL Properties in the Meta Model,” in addition to
searching for property associations based on the AADL specification’s algorithm, the
property lookup methods also interpret the append operator +=>, as well as evaluate
property values that are references to other property values, references to property
constants, and Boolean expressions. Specifically, a PropertyReference object will never
be returned by getSimplePropertyValue, or be a member of the List returned by
getPropertyValueList or obtained from a ModalPropertyValue. Similarly, the only
BooleanValue objects that will be returned will be instances of TRUE and FALSE.
Even more concretely, the property lookup methods will only return instances of TRUE,
FALSE, StringValue, IntegerValue, RealValue, IntegerRangeValue,
RealRangeValue, EnumValue, ClassifierValue, ReferenceValue, and
InstanceReferenceValue7.
5.8.5.1 Modal Property Lookup
When traversing an instance model, the methods getSimplePropertyValue and
getPropertyValueList are sensitive to the current system operation mode. When the
current system operation mode is set, these methods may be safely used with properties
whose value depends on the mode because the system operation mode provides the
context for determining the correct property value. See ????.
When the value associated with a property may depend on the mode, and you are not
using system operation modes, you must use the getPropertyValue method. This
method returns a ModalPropertyValue object, which abstracts the secondary process of
dealing with the modes in which the property has different values. The interface
ModalPropertyValue, and the other classes mentioned in this section, are in package
edu.cmu.sei.aadl.model.properties. The interface has the following methods:
• Method boolean isModal() indicates whether the value depends on modes.
7 Class edu.cmu.sei.aadl.model.instance.InstanceReferenceValue is a subclass of ReferenceValue that
is used on instance models. See Section 5.3.1 “Properties and the Instance Model.”
9/14/2006
107
• Method AadlPropertyValue getValue() returns the property value when it is
non-modal. The exception ModeNotSpecifiedException is thrown if isModal
returns true. The interface AadlPropertyValue is discussed subsequently.
• Method Set getModeContexts() returns a set of ModeContext objects. Each
ModeContext object represents a component whose modes can affect the value
of the property. The modes in scope in a particular ModeContext are returned by
method getModes().
• Method ModeContext[] getModeContextsAsArray() is as above, but returns an
array instead of a set.
• Method AadlPropertyValue getValue(Map modes) gets the property value
under the given mode bindings. The Map maps from ModeContext objects to
Mode objects, indicating the particular mode that each ModeContext is in. The
exception ModeNotSpecifiedException is thrown if a particular mode context
requires a binding and is not provided in the map.
• Method Collection getAllModeBindings() returns all the Maps that make sense
to use with getValue.
• Method Collection getAllValues() returns all the values this property could have
as ReflectiveAadlPropertyValue objects.
It is expected that most users will use the getAllValues method. When analyzing system
instances that represent modal systems, it is best to use the system operation mode
functionality, which removes the complexity of handling modes by allowing the use of
the methods getSimplePropertyValue and getPropertyValueList.
As described in Section 5.7.2 “Nonexistent Property Values,” the value associated with a
property can not only be not present, but also nonexistent. Because null cannot be used
to represent both cases, OSATE contains the interface AadlPropertyValue. This
interface declares the following methods:
• Method boolean exists() returns whether the value exists or not. If exists()
returns false, then the rest of the methods are irrelevant.
• Method boolean isNotPresent() returns whether the value is not present.
• Method boolean isList() returns whether the value is a list or not. Returns false if
!exists() || isNotPresent().
9/14/2006
108
• Method PropertyValue getScalarValue() returns the value if !isList(). The
method throws an UnsupportedOperationException if isList().
• Method List getValue() returns the value as a List of PropertyValue objects. If
!isList(), then the list has a length of one, and the list contains the PropertyValue
object returned by getScalarValue().
The interface ReflectiveAadlPropertyValue extends AadlPropertyValue and adds the
method Map getModeBinding(). This method returns the mode binding for which the
value is associated with the property. The Map is in the same format as required by
ModalPropertyValue.getValue().
Finally, the interface ModeContext is used to abstract whether the modes relevant to a
ModalPropertyValue come from a ComponentImpl, as they will if we are looking up
properties on a component of a declarative model, or a SystemInstance, as they will if
we are looking up properties on a component of an instance model. The difference is that
in the first case we use Mode objects, and in the second case we need to use objects of
type SystemOperationMode (which is a subclass of Mode). The ModeContext
interface hides this problem from the plug-in writer. The interface declares two methods:
• The method String getName() returns the name of the object providing the
modes. This exists mainly to support the “AADL Properties” view plug-in.
• The method List getModes() returns a List of Mode objects provided by the
context.
Most of the time you can avoid having to deal with ModeContext objects by simply
using the ModalPropertyValue.getAllValues() method. But to better explain the
relationship among ModalPropertyValue, AadlPropertyValue, and ModeContext
objects we now present an example based on the specification of
ModalSubcomponents.Impl used in Nonexistent Property Values.
Suppose that sub2 refers the Subcomponent object that models subcomponent sub2 of
ModalSubcomponents.Impl. Let us consider the following code fragment:
(1) ModalPropertyValue mpv = sub2.getPropertyValue("PS", "x"); (2) List contexts = mpv.getModeContexts(); (3) ModeContext mc = (ModeContext) contexts.get(0); (4) List modes = mc.getModes(); (5) Map bindings = new HashMap(); (6) for (Iterator i = modes.iterator(); i.hasNext();) { (7) Mode mode = (Mode) i.next(); (8) bindings.put(mc, mode); (9) AadlPropertyValue apv = mpv.getValue(bindings);
(10) System.out.println("In mode " + mode.getName()); (11) if (!apv.exists()) {
9/14/2006
109
(12) System.out.println(" nonexistent"); (13) } else { (14) if (apv.isNotPresent()) System.out.println(" not present"); (15) else System.out.println(apv.getScalarValue().getValueAsString()); (16) } (17) }
This code fragment is tightly coupled to knowledge that (1) the value does depend on the
mode, and (2) there is exactly one mode context relevant to the property value. In
general, it is hard to know this, and this is why ModalPropertyValue provides the
methods getAllModeBindings and getAllValues. But this code fragment is useful
because it explicates all the steps necessary to get the value of a modal property, even
though in general most of these steps will be performed for you by getAllValues. Before
examining the code, we provide an example output of the fragment:
In mode M1 1 In mode M2 nonexistent In mode M3 not present
This is only a sample of the output, because the exact order in which the results of
looking up in modes M1, M2, and M3 are printed depends on the order in which the
modes are returned by ModeContents.getModes.
While not exercised in this example, executing mpv.isModal() would return true. The
ModeContext object referenced by mc represents the ComponentImpl object that
models ModalSubcomponents.Impl. Invoking getModes() on that object returns a List
containing three Mode objects, one each modeling the modes M1, M2, and M3 declared
in ModalSubcomponents.Impl. To get the value for a particular mode, we must create a
Map to use with ModalPropertyValue.getValue. We do this by iterating over the
Mode objects, see line (6), and putting the specific mode binding into the Map
referenced by bindings on line (8). Were there additional ModeContext objects whose
modes influenced the value, we would have to make sure to bind them to a particular
mode object in bindings as well. On line (9) we finally get the AadlPropertyValue that
represents the value for the particular mode. Once we have an AadlPropertyValue
object we can test whether the value exists, line (11), whether it is not present, line (14),
and get the value, line (15). On line (15) we convert the property value to a String for
output using the method getValueAsString().
5.8.6 Modifying Property Associations
Through the PropertyHolder interface, OSATE also provides a family of methods for
setting and clearing property associations. It is preferable to use these methods instead of
9/14/2006
110
directly manipulating the model because they make sure the resulting model is still legal
AADL by, for example, removing pre-existing property associations for the same
property, checking that the property applies to the component, and checking that the
property value is of the appropriate type.
5.8.6.1 Setting Property Associations
There are four different property setting methods positioned along two axes:
• Whether the property value is a list or not.
• Whether the association is modal or not.
The property setting methods ensure that a property lookup rooted at the given
component will obtain the specified value for the given property in the given modes.
Whether this value affects the property value obtained from a descendent component
depends on the property associations present in the component’s descendents. Each
method returns the PropertyAssociation object that is created.
The method setPropertyValue(PropertyDefinition pd, PropertyValue value), which is
used above in Section 5.4.2 “Class ComponentSecuritySwitch,” creates a new association
for the given property with the given value. The property association applies to all modes,
and any existing property associations for the given property are removed from the
component. The method throws an IllegalArgumentException and leaves the
component unchanged if the property does not apply to the given component or if the
property value is inappropriate for the type of the property. When used with a list-valued
property, this method associates the property with a list whose single value is the given
value.
To associate a general list of values with a list-valued property use the method
setPropertyValue(PropertyDefinition pd, List value), which creates a new association
for the given property with the given list of PropertyValues. The property association
applies to all modes, and any existing property associations for the given property are
removed from the component. The method throws an IllegalArgumentException and
leaves the component unchanged if the property does not apply to the given component,
if the property is not list-valued, or if one of the PropertyValue objects in the list is
inappropriate for the type of the property.
To associate a value with a property in certain modes only, use the methods
setPropertyValue(PropertyDefinition pd, PropertyValue value, List modes) and
setPropertyValue(PropertyDefinition pd, List value, List modes), where modes is a
9/14/2006
111
List of Mode objects. It only makes sense to invoke this method on instances of
ComponentImpl, Subcomponent, and InstanceObject, although this is not checked.
When invoked on a ComponentImpl the Mode objects are restricted to be from the set
of modes returned by that component’s getAllModes method. When invoked on a
Subcomponent, the Mode objects are restricted to be from the set of modes returned by
that subcomponent’s containing component’s getAllModes method. When invoked on
an InstanceObject, the modes are restricted to be SystemOperationMode objects from
the root SystemInstance. Currently, these restrictions are unchecked. In addition to
creating a new property association, these methods may result in changes to the
“inModes” attribute of other property associations for the same property, to ensure that
the property only has one association in the given component for the given set of modes.
These methods throw an IllegalArgumentException under the same circumstances
described above.
These methods all return a PropertyAssociation whose “derived” attribute is false. For
list-valued properties, the “append” attribute is always set to false. If desired, these
attributes can be set to true by manipulating the returned PropertyAssociation object
directly.
A separate set of methods exists for creating contained property associations. These
setContainedPropertyValue methods are like those described above except they have
an additional List parameter that is a list of PropertyHolder objects. This list is used to
initialize the “appliesTo” attribute of the property association, and enumerates a path to a
specific subcomponent or feature. It is checked that this list has at least one element, but
it is not checked whether the path described in the list identifies an actual subcomponent
or feature that makes sense in the given context.
The complete set of methods for setting property values is shown in the table below.
Operation Method
Set property for all modes setPropertyValue(PropertyDefinition pd,
PropertyValue value)
Set list-valued property for all
modes setPropertyValue(PropertyDefinition pd, List value)
Set property for the given
modes setPropertyValue(PropertyDefinition pd,
PropertyValue value, List modes)
Set list-valued property for the
given modes setPropertyValue(PropertyDefinition pd, List value,
List modes)
Set property for the contained
component for all modes setContainedPropertyValue(PropertyDefinition pd,
List appliesTo, PropertyValue value)
9/14/2006
112
Set list-valued property for the
contained component for all
modes
setContainedPropertyValue(PropertyDefinition pd,
List appliesTo, List value)
Set property for the contained
component for the given
modes
setContainedPropertyValue(PropertyDefinition pd,
List appliesTo, PropertyValue value, List modes)
Set list-valued property for the
contained component for the
given modes
setContainedPropertyValue(PropertyDefinition pd,
List appliesTo, List value, List modes)
5.8.6.2 Removing Property Associations
The PropertyHolder interface also contains a set of methods for removing property
associations for a given property from the component. The method
removePropertyAssociations(PropertyDefinition pd) removes all the property
associations for the given property from the component. The method
removePropertyAssociations(PropertyDefinition pd, List modes) removes all the
property associations for the given property for the given modes from the component.
The List of Mode objects has the same constraints as described for setPropertyValue.
This method may remove PropertyAssociation objects from the model, but it may also
modify the “inModes” attribute of PropertyAssociation objects as well, in the case
where the association’s modes are not completely contained in the list of modes to
removed.
A parallel set of methods exists for removing contained property associations. The
complete set of methods for removing property associations and contained property
associations from a component is shown below.
Operation Method
Remove all property
associations removePropertyAssociations(PropertyDefinition pd,
List appliesTo)
Remove property associations
for the given modes removePropertyAssociations(PropertyDefinition pd,
List appliesTo, List modes)
Remove all property
associations from the
contained component
removeContainedPropertyAssociations(
PropertyDefinition pd, List appliesTo)
Remove property associations
for the given modes from the
contained component
removeContainedPropertyAssociations(
PropertyDefinition pd, List appliesTo, List modes)
9/14/2006
113
6 Working with Flows I think this is still correct. Probably could have things added to it.
In this section we discuss how flows can be analyzed by processing declarative AADL
models. First we introduce the concept of specifying flows for component-based system
architectures that are modeled in AADL. Then, we describe the representation of flow
information in the AADL Meta model. Finally, we discuss an analysis plug-in that
performs flow specification validation and determines end-to-end latency on declarative
AADL models.
6.1 Flow Specifications and Flow Instances
A flow specification describes an externally observable flow of information in terms of
application logic through a component. Such logical flows may be realized through ports
and connections of different data types and a combination of data, event, and event data
ports. Flow specifications represent flow sources, i.e., flows originating from within a
component, flow sinks, i.e., flows ending within a component, and flow paths, i.e., flows
through a component from its incoming ports to its outgoing ports.
Flows describe actual flow sequences through components and sets of components across
one or more connections. They are declared in component implementations. Flow
sequences take two forms: flow implementation and end-to-end flow. A flow
implementation describes how a flow specification of a component is realized in its
component implementation. An end-to-end flow specifies a flow that starts within one
subcomponent and ends within another subcomponent. Flow specifications, flow
implementations, and end-to-end flows can have expected and actual values for flow
related properties, e.g., latency or rounding error accumulation.
The purpose of providing the capability of specifying end-to-end flows is to support
various forms of flow analysis, such as end-to-end timing and latency, reliability,
numerical error propagation, Quality of Service (QoS) and resource management based
on operational flows. To support such analyses, relevant properties are provided for the
end-to-end flow, the flow specifications of components, and the ports involved in the
flow to be analyzed. For example, to deal with end-to-end latency the end-to-end flow
may have properties specifying its expected maximum latency and actual latency. In
addition, ports on individual components may have flow specific properties, e.g., an in
port property specifies the expected latency of data relative to its sensor sampling time or
9/14/2006
114
in terms of end-to-end latency from sensor to actuator to reflect the latency assumption
embedded in its extrapolation algorithm.
6.1.1 Flow Specification Declarations
A flow specification declaration in a component type specifies an externally visible flow
through a component’s ports, port groups, or parameters. The flow through a component
is called a flow path. A flow originating in a component is called a flow source. A flow
ending in a component is called a flow sink. Figure 31 illustrates a system type
GPSSystem with three ports and two flow specifications. These are the flows through
GPSSystem and out of GPSSystem that are externally visible. The flow path symbol is
connected to two ports, while flow source symbol connected to one port.
Figure 31: Flow specifications.
The ports identified by the flow specification do not have to have the same data type, nor
do they have to be the same port type, i.e., one can be an event port and the other an
event data port. Multiple flow specifications can be defined involving the same ports.
For example, data coming in through an in port group is processed and data derived from
one of the port group’s contained ports is sent out through different out ports. This
allows logical flows of information through components to be characterized by
attributing flow specifications and the ports involved in flow specifications with relevant
AADL property values. Properties other than the set of predeclared properties can be
introduced through the AADL Property Set concept.
6.1.2 Flow Implementation Declarations
A flow implementation declaration in a component implementation specifies how a flow
specification is realized in the implementation as a sequence of flows through
subcomponents along connections from the flow specification in port to the flow
specification out port. The system implementation for system S1 is shown on the right of
Figure 32. It contains two process subcomponents P1 and P2. Each has two ports and a
flow path specification as part of its process type declaration. The flow implementation
of flow path F1 is shown in both graphical and textual form. It starts with port pt1, as
specified in the flow specification. It then follows a sequence of connections and
9/14/2006
115
subcomponent flow specifications, in our example as the sequence of connection C1,
subcomponent flow specification P2.F5, connection C3, subcomponent flow
specification P1.F7, connection C5. The flow implementation ends with port pt2, as
specified in the flow specification for F1.
Figure 32: Flow Specification & Flow Implementation
Flow implementations can be declared for specific modes and for specific mode
transitions. Furthermore, flow implementations can have mode-specific property values.
This accommodates modeling of flows in modal systems. Figure 33 illustrates how a flow
implementation can be graphically visualized using the selection technique for mode
modeling. A flow implementation can be shown in black by selecting the flow of interest
as a flow specification in the text box. Subcomponent flows and connections that are not
part of the flow are shown in gray. An editor can use this visualization both for
displaying flows and for defining flows. End-to-end flows can be visualized in a similar
manner. The text box has a compartment showing end-to-end flow names. Selection of
one results in showing the flow in black while graying out the rest.
Figure 33: Flow Implementation Selection.
Note that the flow implementation is expressed in terms of flow specifications of its
subcomponents. This allows us to analyze flows in the declarative AADL model one
component at a time. The property values of a flow specification can be validated by the
property values derived from the flow implementation based on flow specification
property values of its subcomponents. In this case, detailed information about the
9/14/2006
116
implementation of these subcomponents is not necessary. This supports a specification-
based low-fidelity analysis of architecture models early in the life cycle before system
details are available.
Once component implementations are known at multiple levels, actual flow properties
such as latency can be propagated up the architecture hierarchy. As we will see later in
this section, such propagation up the architecture hierarchy can even be performed on the
declarative model.
6.1.3 End-To-End Flow Declarations
An end-to-end flow is a logical flow through a sequence of system components, i.e.,
threads, devices and processors. An end-to-end flow is specified by an end-to-end flow
declaration. End-to-end flow declarations are declared in component implementations,
typically the flow implementation in the system hierarchy that is the root of all threads,
processors, and devices involved in an end-to-end flow. The subcomponent identified by
the first subcomponent flow specification referenced in the end-to-end flow declaration
contains the system component that is the starting point of the end-to-end flow.
Succeeding named subcomponent flow specifications contain additional system
components.
Figure 34: An End-To-End Flow Declaration
In the example shown in Figure 32, the flow specification F7 of process P1 may have a
flow implementation that includes flows through two threads which is not included in this
view of the model. The identified subcomponent of the final referenced subcomponent
flow specification contains the last system component of the end-to-end flow.
6.1.4 End-To-End Flow Instances
Flow declarations are associated with individual components. Flow implementations
End-to-end flow declarations are specified in terms of the immediate subcomponents.
For a system instance these flow declarations get recursively expanded the same way
subcomponent declarations results in a hierarchy of component instances in an AADL
9/14/2006
117
instance model or a collection of connection declarations results in a semantic
connection.
Figure 35: Flow Declarations and the System Hierarchy
Figure 35 shows how a flow sink specification gets expanded in a three level system
hierarchy. The flow sink specification FS1 for system S1 is expanded into the
connection C1 and flow sink specification FS2 of process P2, which in turn is expanded
into the connection CC1 and the flow sink specification FS1 of thread T5. In short, the
ultimate flow sink of the flow sink specification of system S2 is the flow sink of thread
T5.
Figure 36 illustrates the expansion of an end-to-end flow declaration into the end-to-end
instance flow in a system instance model. Note that the end-to-end flow declaration is
declared with the component implementation that is the common root of all system
components involved with the end-to-end flow. In our example it is the component
implementation that contains systems S0, S1, and S2 as subcomponents. The ultimate
flow source of the example end-to-end flow is the flow source in thread T0. The ultimate
flow sink is the flow sink in thread T5. The end-to-end instance flow follows the
semantic connection from thread T0 to thread T1, the semantic connection from T1 to
T2, and the semantic connection from T2 to T3. Note that the flow path F1 of system S1
represents the flow through both threads T1 and T2. We have used dashed lines to mark
the end-to-end instance flow in Figure 36.
9/14/2006
118
Figure 36 End-To-End Flow in a System Instance
6.1.5 Textual Flow Declaration Examples
What’s being shown here?
process foo features Initcmd: in event port; Signal: in data port gps::signal_data; Result1: out data port gps::position.radial; Result2: out data port gps::position.cartesian; Status: out event port; flows -- two flows split from the same input Flow1: flow path signal -> result1; Flow2: flow path signal -> result2; -- An input is consumed by process foo through its initcmd port Flow3: flow sink initcmd; -- An output is generated (produced) by process foo and made available -- through its port Status; Flow4: flow source Status; end foo; process implementation foo.basic subcomponents A: thread bar.basic; -- bar has a flow path fs1 from p1 to p2 -- bar has a flow source fs2 to p3 C: thread baz.basic; B: thread baz.basic; -- baz has a flow path fs1 -- baz has a flow sink fsink connections conn1: data port signal -> A.p1; conn3: data port C.p2 -> result1; conn4: data port A.p2 -> C.p1; conn5: event port A.p3 -> Status; connToThread: event port initcmd -> C.reset; flows Flow1: flow path signal -> conn1 -> A.fs1 -> conn4 -> C.fs1 -> conn3 -> result2; Flow3: flow sink initcmd -> connToThread -> C.fsink; -- a flow source may start in a subcomponent,
9/14/2006
119
-- i.e., the first named element is a flow source Flow4: flow source A.fs2 -> connect5 -> status; -- an end-to-end flow from a source to a sink ETE1: end to end flow A.fs2 -> conn4 -> C.fsink; -- an end-to-end flow where the end points are not sources or sinks ETE2: end to end flow A.fs1 -> conn4 -> C.fs1; end foo.basic;
6.2 Flows in the AADL Meta Model
This section describes the representation of flow in the AADL Meta model. This
provides an indication of how flows can be processed. In addition the Meta model
defines how this part of an AADL model is stored as part of an XML document. The
representation of flow declarations is defined in the Flow meta model package of the
AADL Meta model. Flow instance related information is defined in the Instance meta
model package.
6.2.1 Flow Specification Declarations
Flow specifications are represented by an abstract FlowSpec class, which itself is a
subclass of the PropertyHolder class, and the concrete classes for flow source
(FlowSourceSpec), flow sink (FlowSinkSpec), and flow path (FlowPathSpec); see
Figure 37. These classes have references to members of the AbstractPort class in the
same component type, represented by a source and destination reference association - as
appropriate. A flow specification can also refer to an element of a port group. In that
9/14/2006
120
case, the port group is referenced as the context (srcContext or dstContext) of the
source (“src”) or destination (“dst”) reference.
Figure 37: Flow Specification Declaration in the AADL Meta Model.
6.2.2 Flow Implementations and End-To-End-Flows
Figure 38 illustrates the representation of flow implementation declarations and end-to-
end flow declarations in declarative AADL models. The abstract FlowSequence class
represents both flow implementations and end-to-end flows. It is a subclass of the
ModeMember class. A FlowSequence class contains a sequence of FlowElement
objects that alternately represent a reference to a connection or reference pair to a
subcomponent and its flow specification.
9/14/2006
121
Figure 38: Flow Implementation & End-To-End Flow in the AADL Meta Model.
Flow implementations are represented by the abstract FlowImpl subclass and the
concrete subclasses FlowSourceImpl, FlowSinkImpl, and FlowPathImpl. Each of
these concrete subclasses has a reference association to its respective flow specification
class it implements.
Flow implementations contain a sequence of FlowElement objects that alternately
reference a Connection object or a FlowSpec object and the subcomponent it is
contained in as the “flowContext.” The originating source and the final destination port
of a flow implementation are identified by the flow specification being implemented,
thus, are not explicitly recorded as a FlowElement object. Note that these ports are
referenced by the first and last connection of the FlowElement sequence.
A FlowSinkImpl specifies a path from the flow sink spec port through zero or more
connection and subcomponent flow specification pairs (FlowElement) with the last
subcomponent flow specification referring to a flow sink. A FlowSourceImpl specifies a
path from a subcomponent flow source specification represented by one FlowElement
through zero or more connection and subcomponent flow specification pairs
(FlowElement) followed by a FlowElement containing the connection to the destination
port of the flow source implementation. A FlowPathImpl specifies a path from the
(incoming) source port to the (outgoing) destination port of the flow path spec through
zero or more connection and subcomponent flow specification pairs (FlowElement)
ending with a FlowElement that contains the connection to the destination port of the
flow path implementation.
9/14/2006
122
End-to-end flows are represented by the concrete EndToEndFlow class through a
sequence of FlowElement objects with the first referring to the originating
subcomponent and flow specification pair and the remainder representing connection and
subcomponent flow specification pairs (FlowElement).
6.2.3 End-To-End Instance Flows
End-to-end instance flows are represented by the EndToEndFlowInstance class (shown
in Figure 39). Objects of this class are contained in the component instance that
corresponds to the component implementation with the end-to-end flow declaration.
Each end-to-end instance flow object contains a sequence of alternating references to
ConnectionInstance objects and FlowSpecInstance objects.
Figure 39: Flow Instance Representation
Note that the flow instance representation has been added to the AADL Meta model as
result of the AADL Meta model & XML/XMI Interchange Format Annex review in Jan
2005. An implementation of end-to-end flow instantiation will become available with the
next release of OSATE. This capability has not been made use of in the OSATE plug-in
development presentation series.
6.3 The Flow Analysis Plug-in
The flow analysis plug-in described here can be found as the Eclipse/OSATE plug-in
edu.cmu.sei.aadl.flowanalysis. The objective of this plug-in is to demonstrate
• How flow specifications can be processed,
• How flow specification validation and specification-based end-to-end flow
analysis can be achieved by operating on the declarative AADL model,
• How an analysis written for declarative models can be reused to operate on
instance models.
9/14/2006
123
First, we focus on flow specification validation, and then on end-to-end flow analysis.
6.3.1 Meeting Flow Requirements
Flow specification declarations in component types can have properties that reflect
expected flow characteristics that act as requirements. Flow implementations are
expected to satisfy those requirements. Flow implementations are validated against the
flow specification in terms of properties provided by the subcomponent flow
specifications that are part of the flow implementation.
The AADL standard has pre-declared three latency related properties:
Latency: Time applies to (flow, connections);
The Latency property specifies the maximum amount of elapsed time allowed between
the time the data or events enter the connection or flow and the time it exits.
Expected_Latency: Time applies to (flow);
The Expected_Latency property specifies the expected latency for a flow specification.
The intent is that the actual latency must not exceed the expected latency. The AADL
language does not enforce this constraint; it is the responsibility of consumers of this
property to verify that this is the case.
Actual_Latency: Time applies to (flow);
The Actual_Latency property specifies the actual latency as determined by the
implementation of the end-to-end flow through semantic connections.
In our flow analysis plug-in we will make use of the Latency property and the
Expected_Latency property. The Latency property associated with a flow specification
is interpreted to represent the latency the component is expected to satisfy. The latency
property associated with the flow implementation represents the latency determined by
the connection latencies and the subcomponent flow specification latencies. The
Expected_Latency property is used on end-to-end flows to indicate the desired latency,
while the Latency property of the end-to-end flow represents the calculated latency
determined by the connection latencies and the subcomponent flow specification
latencies.
The Actual_Latency property can be used to recursively propagate latency information
up the system hierarchy.
The flow specification validation is implemented by checking that every flow
implementation satisfies the corresponding flow specification properties. This is
achieved by traversing the declarative AADL model and processing through the
9/14/2006
124
caseFlowImpl method. This method handles all three subclasses of flow
implementations: flow source implementations, flow sink implementations, and flow path
implementations. The code is shown in below. We iterate over all flow elements that
make up the flow implementation and add up the latency values of the connections and
subcomponent flow specifications that we encounter. We determine whether we are
dealing with a connection or a subcomponent flow specification by testing for
isConnectionReference(). The AADL front-end has already made sure that the flow
element sequence alternates between connection references and subcomponent flow spec
references, therefore we do not have to track which element we processed last. We do all
the arithmetic by retrieving the latency values with respect to a specific unit, in our case
in micro seconds. We take advantage of the predeclared property definitions available in
the edu.cmu.sei.aadl.property.predeclared package. Once the result is added up we
store the result as Latency property value with the flow implementation and compare it
to the Latency property of the flow specification. The property value is set by creating a
new IntegerValue object, setting its value and measurement unit, and then performing a
setPropertyValue(PredeclaredProperties.LATENCY,newpv); on the flow
implementation object.
public Object caseFlowImpl(FlowImpl fi) { FlowSpec fs = fi.getXImplement(); EList fel = fi.getFlowElement(); double result = 0; for (Iterator it = fel.iterator(); it.hasNext();){ FlowElement fe = (FlowElement)it.next(); if (fe.isConnectionReference()){ Connection conn = fe.getConnection(); IntegerValue cpv = (IntegerValue)conn.getSimplePropertyValue( PredeclaredProperties.LATENCY); if (cpv != null) { result = result + cpv.getScaledValue(PredeclaredProperties.MICROSEC); } } else { FlowSpec fefs = fe.getFlowSpec(); if (fefs != null){ IntegerValue fefspv = (IntegerValue) fefs.getSimplePropertyValue( PredeclaredProperties.LATENCY); if (fefspv != null) { result = result + fefspv.getScaledValue(PredeclaredProperties.MICROSEC); } else { // handle the case when no latency is specified } } // store the result as flow implementation latency IntegerValue newpv = PropertyFactory.eINSTANCE.createIntegerValue(); newpv.setNewValue((long) result); newpv.setUnitLiteral(PredeclaredProperties.MICROSEC); fi.setPropertyValue(PredeclaredProperties.LATENCY,newpv);
9/14/2006
125
// now we compare the result to the latency in the flow spec IntegerValue fspv = (IntegerValue) fs.getSimplePropertyValue( PredeclaredProperties.LATENCY); if (fspv != null) { double fslv = fspv.getScaledValue( PredeclaredProperties.MICROSEC); if (result > fslv) { reportError(fi, "Flow implementation latency " + result + "exceeds flow spec latency " + fslv); } }
6.3.2 Handling of Missing Latency Properties
This basic analysis algorithm can be refined in several ways.
First, we deal with the case when a subcomponent flow specification does not have a
Latency property value and the subcomponent is a thread. In this case we can infer the
worst case latency from the thread characteristics. If the thread is a periodic thread and
the incoming connection is a delayed connection, then the period of the thread determines
the latency contribution of the thread. If the thread is periodic and the incoming
connection is an immediate connection or the thread is an aperiodic or sporadic thread
then the latency contribution is the completion time, whose worst case is the thread
deadline.
We add code to track whether the incoming connection was a delayed data connection.
We do that every time we encounter a connection reference by checking the timing
attribute of the DataConnection.
boolean wasDelayedConnection = false; for (Iterator it = fel.iterator(); it.hasNext();) { FlowElement fe = (FlowElement) it.next(); if (fe.isConnectionReference()) { Connection conn = fe.getConnection(); if (conn instanceof DataConnection && ((DataConnection)conn).getTiming() == ConnectionTiming.DELAYED_LITERAL) { wasDelayedConnection = true; } else { wasDelayedConnection = false; } IntegerValue cpv = (IntegerValue) conn.getSimplePropertyValue( PredeclaredProperties.LATENCY);
Then we deal with the case when a Latency property value could not be found and the
subcomponent is a thread subcomponent. In that case we retrieve the dispatch protocol
from the thread classifier. We use the getClassifier() method that is defined for the
ThreadSubcomponent to get the classifier. If the thread is periodic and the previous
(incoming) connection was delayed we retrieve the period and add it, otherwise we
retrieve the deadline and add it.
} else {
9/14/2006
126
Subcomponent sc = fe.getFlowContext(); if (sc instanceof ThreadSubcomponent){ ThreadClassifier tc = ((ThreadSubcomponent) sc).getClassifier(); EnumLiteral dp = tc.getDispatchProtocol(); if (dp == PredeclaredProperties.PERIODIC && wasDelayedConnection) { IntegerValue period = (IntegerValue) sc.getSimplePropertyValue( PredeclaredProperties.PERIOD); if (period != null){ result = result + period.getScaledValue(PredeclaredProperties.MICROSEC); } else { reportInfo(sc, "Thread subcomponent has no flowspec latency " + "or periodic thread period"); } } else { IntegerValue deadline = (IntegerValue) sc.getSimplePropertyValue( PredeclaredProperties.DEADLINE); if (deadline != null){ result = result+deadline.getValue(); } else { reportInfo(sc, "Thread subcomponent has no flowspec latency " + " or thread deadline"); } } } else { reportInfo(sc, sc.getComponentType().getCategory().getName() + " subcomponent has no flowspec latency for flow " + fefs.getName()); } }
6.3.3 Propagation of Flow Latency Information
The second refinement is to record the flow implementation result as the flow
specification latency if the flow specification does not have such a property value. If we
do this and traverse the AADL model according to the use hierarchy of component
implementations we will ensure that flow specification latency property values have been
filled in before they are used. We accomplish this by adding a caseComponentImpl
method that is invoked by the processBottomUpComponentImpl() method. This
traversal method visits only component implementations and does so bottom up by
processing component implementation classifiers before they are referenced by
subcomponent declarations. This traversal method is invoked by the analysis action
method doAaxlAction. The caseComponentImpl method retrieves the list of flow
implementations and invoke the processElist method for switch-based processing.
Instead, we simply could have invoked a second traversal method to process its content
according to the case methods defined for the flow analysis.
// inside the caseFlowImpl method // set the sum value for the flow implementation IntegerValue newpv = PropertyFactory.eINSTANCE.createIntegerValue(); newpv.setNewValue((long)result); newpv.setUnitLiteral(PredeclaredProperties.MICROSEC); fi.setPropertyValue(PredeclaredProperties.LATENCY,newpv); // now we compare the result to the latency in the flow spec
9/14/2006
127
IntegerValue fspv = (IntegerValue)fs.getSimplePropertyValue( PredeclaredProperties.LATENCY); if (fspv != null){ public Object caseComponentImpl(ComponentImpl ci) { self.processEList(ci.getFlowSequence()); // alternative: self.processPreOrderAll(ci); return DONE; } public void doAaxlAction(AObject obj){ AObject root = obj.getAObjectRoot(); AadlProcessingSwitch flowLatencySwitch = new FlowLatencyAnalysisSwitch(getMarkerReporter()); if (root instanceof AadlSpec) { flowLatencySwitch.processBottomUpComponentImpl((AadlSpec)root);
6.3.4 Reusing the Analysis for Instance Models
Finally, we refine the plug-in to allow the use of the analysis methods on instance models
as well. This is feasible for analyses that can produce results based on processing of
declarative AADL models. In this case we will traverse the AADL instance model in
prefix order, i.e., bottom up in terms of the instance hierarchy, by using the
processPreOrderComponentInstance method. For each component instance we
encounter, we simply delegate the processing to the appropriate component
implementation of the subcomponent that was instantiated as component instance. This
is done with the caseComponentInstance method and for the system instance object
with the caseSystemInstance method. The caseComponentInstance method checks for
non-null component implementation classifiers; this is done to handle instance models
with subcomponent classifiers of leaf component instances being component type only.
public void doAaxlAction(AObject obj){ AObject root = obj.getAObjectRoot(); AadlProcessingSwitch flowLatencySwitch = new FlowLatencyAnalysisSwitch(getMarkerReporter()); if (root instanceof AadlSpec){ flowLatencySwitch.processBottomUpComponentImpl((AadlSpec)root); } else { flowLatencySwitch.processPreOrderComponentInstance( (SystemInstance) root); } reportDone(root,"Flow Latency Checking"); } public Object caseComponentInstance(ComponentInstance ci) { Subcomponent sub = ci.getSubcomponent(); ComponentImpl cii = sub.getComponentImpl(); if (cii == null) return DONE; self.processPreOrderAll(cii); return DONE; } public Object caseSystemInstance(SystemInstance ci) { SystemImpl si = ci.getSystemImpl(); self.processPreOrderAll(si); return DONE;
9/14/2006
128
}
6.4 Specification-Based End-To-End Flow Analysis
The objective of this analysis plug-in is to demonstrate the ability to perform quantitative
analysis with precise results on low-fidelity architecture models. The particular use
scenario for this plug-in is an avionics display system for which we are trying to
determine an upper bound on the arrival rate of certain events. The particular event
stream we are interested in is the request for different page content by the pilot by
selecting a different page from the multi-function display menu. The request is issued by
the pilot pushing a virtual button on the display for the menu entry of interest. The
application logic is designed such that a new request can only be issued once the
requested page has been shown. Therefore, by determining the minimum latency for
changing the page content we can bound the arrival rate of such page requests.
6.4.1 The Display System Model Scenario
We can perform this analysis on a model of the avionics system that only represents
subsystems. Figure 40 illustrates the relevant subsystems and the end-to-end flow
specification in terms of port group connections and subsystem flow specifications. The
end-to-end flow start with the Cockpit display goes through several subsystems to the
flight director and returns the resulting new page along the reverse path. We used port
groups to indicate that possibly multiple port connections may exist between two
subsystems. From a flow specification perspective the details of such connections are
irrelevant.
Figure 40: A Subsystem End-To-End Flow
9/14/2006
129
The corresponding textual AADL model is shown below defining the avionics display
system implementation that contains the subsystems and the end-to-end flow
specification. Note the Latency property on the end-to-end flow.
system implementation Flight_System.impl subcomponents Pilot_Display: device Display.MFD; Pilot_DM: system Display_Manager.impl; PCM: system Page_Content_Manager.impl; FM: system Flight_Manager.impl; FD: system Flight_Director.impl; connections menu_cmd_to_DM: data port Pilot_Display.Menu_Cmd_Pushed -> Pilot_DM.Menu_selection_from_Display; menu_cmd_to_PCM: event data port Pilot_DM.New_Page_Request_To_PCM -> PCM.New_Page_Request_From_DM; menu_cmd_to_FM: event data port PCM.New_Page_Request_To_FM -> FM.New_Page_Request_From_PCM; menu_cmd_to_FD: event data port FM.New_Page_Request_To_FD -> FD.New_Page_Request_From_FM; page_to_FM: event data port FD.New_Page_Content_To_FM -> FM.New_Page_Content_from_FD; page_to_PCM: event data port FM.New_Page_Content_To_PCM -> PCM.New_Page_Content_from_FM; page_to_DM: event data port PCM.New_Page_Content_To_DM -> Pilot_DM.New_Page_Content_from_PCM; page_to_Display: data port Pilot_DM.New_Page_Image_To_Display -> Pilot_Display.Page_To_Show; flows get_new_page: end to end flow pilot_Display.Menu_Entry_Selected -> menu_cmd_to_DM -> Pilot_DM.cmd_request -> menu_cmd_to_PCM -> PCM.cmd_request -> menu_cmd_to_FM -> FM.cmd_request -> menu_cmd_to_FD -> FD.process_page_request -> page_to_FM -> FM.show_page -> page_to_PCM -> PCM.show_page -> page_to_DM -> Pilot_DM.show_page -> page_to_Display -> Pilot_Display.Show_Page { latency => 300 ms; }; end Flight_System.impl;
In this particular design each subsystem is implemented as a partition in a time
partitioned system. This means that each partition and the threads contained in its execute
once per minor frame, i.e., once per partition period. As a result, each time the flow
crosses a partition boundary a frame delay latency is added corresponding to the partition
period. To model this fact we introduce a new property that can be associated with
systems called Partition_Latency and give it a default value of 50 ms. By assigning a
default value we do not have to explicitly specify a partition period value for each
subsystem.
property set SEI is Partition_Latency: Time => 50 ms applies to ( system ); end SEI;
9/14/2006
130
6.4.2 The Partition Latency Analysis
The partition latency analysis operates as follows. It first takes into account that the
display device has some latency in processing the button push. This processing is
modeled as flow latency in the display device. Then we take into account each time the
flow crosses from one partition to another. Finally, the last subcomponent listed in the
flow is the display device and we account for the time it takes to refresh the display itself.
The partition latency analysis plug-in is similar to the flow specification validation plug-
in. In this case we redefine the caseEndToEndFlow method to process a sequence of
flow elements.
First we handle the display device by setting its latency as the initial result value (or to
zero if no latency value exists).
public Object caseEndToEndFlow(EndToEndFlow etef) { EList fel = etef.getFlowElement(); double result = 0; Subcomponent sc = null; if (fel.isEmpty()) return DONE; Iterator it = fel.iterator(); FlowElement fe = (FlowElement)it.next(); sc = fe.getFlowContext(); FlowSpec fefs = fe.getFlowSpec(); IntegerValue fefspv = (IntegerValue) fefs.getSimplePropertyValue( PredeclaredProperties.LATENCY); double latency = 0; if (fefspv != null) { result = fefspv.getScaledValue(PredeclaredProperties.MICROSEC); }
Then we are iterating over the remaining flow elements to add any latency due to the
connection and the partition crossing latencies. This is done by adding the partition
latency property value for every subsequent system subcomponent we encounter.
while (it.hasNext()){ fe = (FlowElement)it.next(); if (fe.isSubcomponentFlowSpecReference()) { sc = fe.getFlowContext(); pl = (IntegerValue) sc.getSimplePropertyValue( CheckFlowLatency.partitionLatency); if (pl != null) { partlatency = ((IntegerValue) pl).getScaledValue( PredeclaredProperties.MICROSEC); result = result + partlatency; } else { reportInfo(sc, sc.getComponentType().getCategory().getName() + " subcomponent has no partiton latency"); } } }
9/14/2006
131
The property definition for the partition latency has been initialized in the
initPropertyReferences method. This improves the efficiency of the analysis since the
property definition does not have to be repeatedly looked up from string names.
protected void initPropertyReferences() { partitionLatency = lookupPropertyDefinition("SEI", "Partition_Latency"); }
Once the end-to-end latency is determined, it is compared to the latency or expected
latency specified for the end-to-end flow.
PropertyValue epv = etef.getSimplePropertyValue(PredeclaredProperties.LATENCY); if (epv == null) { epv = etef.getSimplePropertyValue( PredeclaredProperties.EXPECTED_LATENCY); } if (epv != null) { double val = ((IntegerValue) epv).getScaledValue( PredeclaredProperties.MICROSEC); reportInfo(etef,"Expected end-to-end flow latency is " + AadlUtil.usValueToMS(val) + " ms"); if (result > val) { reportError(etef,"End-to-end flow latency " + AadlUtil.usValueToMS(result) + " ms exceeds specified latency " + AadlUtil.usValueToMS(val) + " us"); } }
6.4.3 Partition Latency Analysis Refinement
The latency calculated in the above plug-in provides a lower bound on the end-to-end
latency. This partition latency analysis can be refined in the following way. We can take
into account any flow specification latency that may have been specified for each
subsystem. If that flow specification latency exceeds the partition latency of the
succeeding partition it increases the latency to the next frame. Flow specification latency
may be larger than a partition period because the flow within a subsystem may involve
multiple threads and the threads may communicate through a delayed connection or the
thread executes at a period larger than a partition, thus, spans multiple partition periods.
The high-lighted portions of the code segment shown below accomplish this.
In the first high-lighted section we add any communication latency to the accumulated
computational latency.
In the second section we have encountered a partition and we need to determine the
latency to be added due to partition. If the partition latency is greater than the
computational latency from previous components then the partition latency is added; if
the computational latency is larger and the partition latency is non-zero then we round up
9/14/2006
132
to the next frame of the partition; and if the partition latency is zero, then we add the
computational latency.
In the third high-lighted section we determine the flow specification latency for the
current subcomponent.
In the fourth high-lighted section, we determine the computational latency contributed by
the current subcomponent as a partition to be passed on for the next subcomponent. The
larger of the flow specification latency the partition latency is passed on.
In the fifth high-lighted section we determine the computational latency contributed by
the current subcomponent if it is not a partition. In this case the larger of its flow
specification latency or partition latency is added to the computational latency from the
previous subcomponent.
In the final highlighted section we add any computational latency not accounted for
before as the last step of calculating the end-to-end latency.
if (conn != null) { PropertyValue cpv = conn.getSimplePropertyValue( PredeclaredProperties.LATENCY); if (cpv != null) { double val = ((IntegerValue) cpv).getScaledValue( PredeclaredProperties.MICROSEC); prevlatency = prevlatency + val; } } } else { sc = fe.getFlowContext(); pl = (IntegerValue) sc.getSimplePropertyValue( CheckFlowLatency.partitionLatency); partlatency = 0; if (pl != null) { partlatency = ((IntegerValue) pl).getScaledValue( PredeclaredProperties.MICROSEC); result = result + (partlatency >= prevlatency ? partlatency : (partlatency == 0 ? prevlatency : (((int) prevlatency/partlatency) + 1) * partlatency)); } else { reportInfo(sc, sc.getComponentType().getCategory().getName() + " subcomponent has no partiton latency"); } fefs = fe.getFlowSpec(); fefspv = (IntegerValue) fefs.getSimplePropertyValue( PredeclaredProperties.LATENCY); latency = 0; if (fefspv != null) { latency = fefspv.getScaledValue(PredeclaredProperties.MICROSEC); } if (partlatency != 0) { prevlatency = (latency > partlatency) ? latency : partlatency; } else { prevlatency = prevlatency +
9/14/2006
133
((latency > partlatency) ? latency : partlatency); } } } /* account for partition feeding a non-partition at the end */ result = result + prevlatency;
6.5 Latency Analysis with Instance Models
The above two latency analyses have illustrated the possibility of performing latency
analysis on declarative models. However, such an analysis is not always possible on
declarative models. For example, if the latency calculations are dependent on particular
execution platform bindings the analysis must be performed on an instance model. This
is the case if the connection latency is different for communication within the same
processor as compared to communication between processors over a network.
In those cases the analysis methods will want to operate on the flow information recorded
with the instance model. The relevant parts of the instance model have been shown in
Figure 39.
9/14/2006
135
7 Writing Eclipse/OSATE Actions Fill this in. Move some of the error handling discussion from property example to here? Talk
about AaxlReadOnlyAction in more detail: implelemnts 2 callback interfaces. What exactly does its
run method do? What are its limitations. Hooking up actions to the UI: toolbars and menubars.
Popup menus. Example, putting the model statistics action into a popup menu. Give pointers to
the Help pages that I have found on the subject.
Also, how to distribute a plug-in. Creating features, update sites, etc.
9/14/2006
137
8 Managing the Results of an OSATE Plug-in This is still a stub.
There are several mechanisms to manage the results of an OSATE plug-in. They are
summarized here and elaborated in subsequent sections.
8.1 Comparison of Result Management Mechanisms
8.1.1 Use of Eclipse Markers
• separation of recording and reporting - The plug-in records them, the user chooses
when to view them.
• Persistent beyond the execution of the plug-in. Markers are kept with the
resources (files).
• Auto-reset on plug-in execution.
• Categories of markers for different plug-ins.
• Markers can also be used non-persistently by changing the value of its persistent
attribute in the marker definition (see above).
• Decoration icon on the resource in the Navigator.
• Marker location indicators on the sidebar of an open editor window.
• Markers are accessible programmatically via org.eclipse.core.resources.
For more details see Section 9 “Persistent Markers with AADL Models.”
8.1.2 Use of SWT Dialog box
• Immediate reporting.
• Synchronous or asynchronous popup. Synchronous popup requires user
confirmation (ok button) before letting the user proceed. Asynchronous popup
produces the window, but lets the user change the focus without closing the
window.
• Messages only exist for the duration of the popup.
8.1.3 Use of AADL Properties
• Persistently kept in the AADL model.
• New properties can be introduced through the property set construct in AADL
9/14/2006
138
• AADL properties, both predeclared and those introduced through property sets,
are accessible programmatically via the AADL model API for AADL properties;
results of one plug-in can be used by other plug-ins
• All AADL properties are visible via AADL model via AADL model presentation
mechanisms such as the AADL Property Viewer, Graphical editor etc.
8.1.4 Use of Adapters on AADL Models
• In-core addition of information to AADL model without requiring extensions to
the model representation itself
• Information is accessible programmatically through the AADL model objects by
utilizing an adapter concept. A generic set of adapters for each class in the AADL
meta model and an adapter factory have already been generated by EMF. They
can be subclassed for plug-in–specific uses.
• Allows model object specific information to be passed in context between
different passes of one OSATE plug-in or between plug-ins executed in
succession.
8.1.5 Use of the File System
• Persistent record in file system
• Visible a resource in Navigator
• Permits use of representation appropriate for analysis or generation tool (e.g.,
generation of textual AADL or MetaH)
• Supports interchange representations of external tools
8.1.6 Use of Meta Model-Based XML Documents
• Use EMF to define meta model for target object model/XML; this can be
achieved by importing an existing XML schema of an object model or by creating
a meta model interactively.
• Generate the target object model in-core by traversing the AADL object model;
add the root object as content of a (EMF) resource; call on save method of
resource to store as XML document
• This method is used to generate the AADL instance model
9/14/2006
139
9 Persistent Markers with AADL Models This section needs to be rewritten because the error reporter have changed a lot since this was
written.
Eclipse provides a marker mechanism to associate messages of different categories with
resources (e.g., files). These markers can be of different severity, such as error, warning,
and informational. Markers have a message text and a location into the resource. The
location can be resource type specific. For example, line numbers are used for text
resources, while URIs are used for XML-based documents such as AADL model in XML
(files with the extension aaxl). The markers are shown in the “Problem” view when the
resource is selected in the “Navigator” or “Package Explorer” view. When a marker is
double-clicked in the “Problem” view, Eclipse causes the appropriate editor to go to the
location in the resource associated with the marker. Markers have a type that can be used
to filter and sort markers in the “Problems” view.
This section describes how to declare new marker types and how to manage markers
using a MarkerReporter object. In this section, as a running example, we augment the
Model Statistics plug-in from Section 0 “
9/14/2006
141
A First Plug-in: Model Statistics” to report its results using its own marker type.
9.1 OSATE Marker Types
Markers are associated with a type from an extensable marker type hierarchy. This type
can be used to filter and sort markers in the “Problems” view. The Eclipse API also
provides methods for manipulating markers based on their type; this API is described in
XXX. Marker types are thus used to differentiate results originating from different plug-
isn and to group results that are conceptually similar. OSATE defines two AADL-
specific markers as subtypes of the Eclipse-provided marker type
org.eclipse.core.resources.problemmarker:
• Marker type edu.cmu.sei.aadl.model.AadlTextMarker is used by the AADL
compiler front-end to record syntax and semantic problems with respect to the
processed textual AADL.
• Marker type edu.cmu.sei.aadl.model.AadlObjectMarker is used to mark AADL
object models.
By default, AaxlReadOnlyAction creates markers of type AadlObjectMarker, but
generally an OSATE plug-in should create markers of a subtype of AadlObjectMarker
so that its results may be differentiated from the results of other plug-ins.
9.1.1 Defining New Marker Types
Marker types are defined in a plug-in’s manifest file, plugin.xml, using the Eclipse
extension point org.eclipse.core.resources.markers. Like all extensions points, they
have an id used to identify the extension point within Eclipse, and a human-readable
name. We can declare a new ModelStatisticsObjectMarker marker type for use by the
Model Statistics plug-in by adding the following declaration to it’s plug-in manifest file:
<plugin id="edu.cmu.sei.osate.statistics" ...> <!-- ... --> <extension id="ModelStatisticsObjectMarker" name="Model Statistics Marker" point="org.eclipse.core.resources.markers"> <super type="edu.cmu.sei.aadl.model.AadlObjectMarker"/> <persistent value="true"/> </extension> </plugin>
The super type of the marker type is identified by its fully qualified name—its id
qualified by the name of the plug-in in which it is declared. Marker types can have
multiple super types, each declared using a separate super element. Setting the
persistent attribute to true insures that Eclipse will save the marker with the resource,
9/14/2006
142
and thus the marker persists between runs of Eclipse. If the persistent attribute is set
to false, the marker will be forgotten upon exiting Eclipse.
You can use the new marker type in your plug-in by creating a new MarkerReporter
that associates the marker type with a particular resource; this is described in the
following subsection. After defining a new marker type in your plug-in, you may need to
make sure that the “Problems” does not filter it out the next time you execute your
development runtime workbench. To do this, click on the filters icon in the “Problems”
view menubar; see Figure 41. Make sure that the new marker type is “checked” in the
“Show items of type” list in the “Filters” dialog box; see Figure 42.
Figure 41: The "filters" button in the "Problems" view menubar.
9/14/2006
143
Figure 42: Enabling the "Model Statistics Marker" in "Filters" dialog box. The marker type must be "checked" for it to
appear in the "Problems" view.
9.2 Managing Markers with MarkerReporter
OSATE plug-ins use instances of the the class MarkerReporter in package
edu.cmu.sei.aadl.model.pluginsupport to create and manage markers. A
MarkerReporter creates markers of a particular marker type for a particular EMF
resource. Usually you let AaxlReadOnlyAction create the MarkerReporter for you,
but you can create secondary MarkerReporter objects if your plug-in reports several
types of markers. Because AaxlReadOnlyAction automatically creates a
9/14/2006
144
MarkerReporter, we describe how to use a MarkerReporter before describing how to
create new instances of MarkerReporter.
9.2.1 Reporting Markers
Previous examples have described the methods reportInfo, reportWarning, and
reportError in the classes AaxlReadOnlyAction (Section 3.3.2 “The Model Statistics
Action Code”) and ForAllAObject (Section 4.3.5 “Reporting Markers During a
Traversal”). These methods are implemented by delegating to methods of the same name
in a MarkerReporter instance. An instance of AaxlReadOnlyAction delegates to a
MarkerReporter that it creates (see below). An instance of ForAllAObject is given a
reporter instance when it is created; see the example in Section 4.3.5 “Reporting Markers
During a Traversal.” If no reporter is provided, it uses a reporter instance that writes the
markers to standard output. Within a subclass of AaxlReadOnlyAction, the reporter is
obtained using the method getMarkerReporter(). Within a subclass of ForAllAObject,
the reporter is obtained using the field reporter.
Even though a MarkerReporter is associated with a particular EMF Resource, it can be
used to report markers on any AObject. The reporter keeps track of the number of
markers placed on objects outside of the resource associated with the reporter. The
number of these “external” markers can be retrieved using the method externalErrors().
This functionality is used, for example, by the system instantiation plug-in: the same
MarkerReporter is used to report issues with both the declarative model and the
generated instance model. Markers placed on the instance model are counted as external,
and the plug-in displays a dialog box warning that the instance model has errors if
externalErrors() returns a non-zero value.
public class InstantiateAadl extends AaxlReadOnlyAction { // ... public void doAaxlAction(AObject obj) { // ... SystemImpl si = (SystemImpl) obj; InstantiateModel instantiateModel = new InstantiateModel(getMarkerReporter()); instantiateModel.buildInstanceModelFile(si); if (getMarkerReporter().externalErrors() > 0) { MessageDialog.openWarning(getShell(), "Instantiation Warning", "The instantiated model may have errors or warnings. " + "Please select the generated instance model for " + "additional messages"); } } }
We do this because the “Problems” view can be configured to only show the markers for
the currently selected resource, and if so, if the instantiated system as errors, they will be
9/14/2006
145
filtered out of the problem view until the user selects the instance model in the
“Navigator.” Therefore, we have the plug-in inform the user of the existence of the
markers so that they know to look for them.
9.2.2 Creating MarkerReporter Objects
New MarkerReporter objects are created using the factory methods
MarkerReporter.createMarkerReporter(Resource rsrc) and
MarkerReporter.createMarkerReporter(Resource rsrc, String markerType). The
single-parameter factory method creates a new reporter that creates markers of type
AadlObjectMarker. The two-parameter method creates markers of the named marker
type. The marker type name must be qualified by the name of the plug-in in which it is
declared. For example, the full name of our ModelStatisticsObjectMarker is
edu.cmu.sei.ostate.statistics.ModelStatisticsObjectMarker. As a side effect of
creating a MarkerReporter, all the markers of the associated marker type are removed
from the associated resource. This enures that only the newest marker results will be
displayed on the resource. It means, however, that a plug-in that does not declare its own
marker type runs the risk of deleting markers created by other plug-ins.
Because many plug-ins need to create markers, the abstract OSATE action class
AaxlReadOnlyAction automatically creates a new MarkerReporter when the action is
invoked. This frees the plug-in writer from the tedium of getting the initial EMF
Resource object. In most cases, this reporter object is only needed to initialize the model
traversals used by the action; it can be obtained using the method getMarkerReporter().
The marker type associated with the reporter is controlled by overriding the method
AaxlReadOnlyAction.getMarkerType() that returns the name of the marker type to use.
The default implementation of this methods returns
"edu.cmu.sei.aadl.model.AadlObjectMarker".
It is thus trivial to change the Model Statistics plug-in to use markers of type
ModelStatisticsObjectMarker instead of the default AadlObjectMarker. We update
the class DoModelStatistics as shown below.
public class DoModelStatistics extends AaxlReadOnlyAction { private static final String MARKER_TYPE = "edu.cmu.sei.osate.statistics.ModelStatisticsObjectMarker"; public String getMarkerType() { return MARKER_TYPE; } // ... }
9/14/2006
146
9.2.2.1 Creating Secondary MarkerReporter Objects
If your plug-in needs to create additional markers of different marker types, you can
create secondary MarkerReporter objects to manage them. You simply create
additional MarkerReporter instances using the factory method
MarkerReporter.createMarkerReporter(Resource rsrc, String markerType) in your
doAaxlAction implementation. Pass these instances to the model traversals that need
them instead of using passing the reporter returned by getMarkerReporter(). The EMF
resource that contains a model object can be obtained using the method
EObject.eResource(). You can make sure that you use the same Resource as the
primary MarkerReporter by getting the resource from the root object passed to the
doAaxlAction method. For example, the action fragment below creates a plug-in that
executes in two passes and uses different markers for each pass.
public class TwoPassAction extends AaxlReadOnlyAction { private final String PASS1_MARKER_TYPE = ...; private final String PASS2_MARKER_TYPE = ...; public String getMarkerType() { return PASS1_MARKER_TYPE; } public void doAaxlAction(final AObject root) { // Create first pass final ForAllAObject pass1 = new ForAllAObject(getMarkerReporter()) { ... }; // Create second pass final MarkerReporter secondaryReporter = MarkerReporter.createMarkerReporter( root.eResource(), PASS2_MARKER_TYPE); final ForAllAObject pass2 = new ForAllAObject(secondaryReporter) { ... }; pass1.processPreOrderAll(root); pass2.processProOrderAll(root); } }
9.2.3 Limiting the Number of Markers
Because Eclipse can become cranky when the “Problems” view contains a large number
of messages, MarkerReporter objects stop creating markers if a maximum marker count
is exceeded. When the count is exceeded the reporter creates a marker indicating this fact
so that the user knows that only a subset of the plug-ins results are being reported. The
default maximum value is 500. After creating a reporter, you can set the maximum
number of markers it should create using the method setMaxMarkerCount(int max).
You can query the number of markers it has created using getMarkerCount(). The
9/14/2006
147
predicate tooManyMarkers() returns whether the maximum marker count has been
exceeded.
9.2.4 Deleting Markers
The method deleteMarkers() removes all the markers of the marker type associated with
the MarkerReporter from the Resource associated with the MarkerReporter. This
method is invoked when the reporter is created. Because this method does not remove
any markers from other resources, the marker count is not reset to zero but it is instead
reset to the number of external markers created by the reporter.
The static method MarkerReporter.deleteAllMarkers(Resource rsrc) removes all the
markers attached to the given EMF resource. This method does not affect the marker
counts of any existing MarkerReporter instances.
9.3 Reporting Errors in the Plug-in
Class MarkerReporter also contains static methods that a plug-in can use to report
internal errors to the Eclipse “Error Log” view. This is useful if the plug-in catches an
exception or detects that it is unable to proceed for some reason, e.g., it has discovered a
null reference. It is preferable that the plug-in also produce an error dialog when it
discovers an error because Eclipse does not always bring the “Error Log” to the front
when new items are added to it, and thus the user is not always aware that an error has
occurred. The static method MarkerReporter.internalError(Exception e) logs the
given exception, while the static method MarkerReporter.internalError(String
message) logs the given error message. For example, the code below yields the error log
shown in Figure 43.
public class DoIt extends AaxlReadOnlyAction { public void doAaxlAction(final AObject obj) { MarkerReporter.internalError("This is an internal error message"); try { final Object o = null; o.toString(); } catch(NullPointerException e) { MarkerReporter.internalError(e); } MessageDialog.openError(getShell(), "Error!", "Errors during plug-in execution."); } }
Double-clicking on the error log entry brings up further details, including the stack trace
(if any) included in the exception. For example, see Figure 44.
9/14/2006
148
Figure 43: "Error Log" entries after executing example code.
Figure 44: Viewing the details of an error log entry.
9/14/2006
149
10 Packages Provided by the OSATE Plug-ins What else do we want to expose here?
Java Package OSATE Plug-in
edu.cmu.sei.aadl.model.component edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.component.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.component.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.connection edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.connection.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.connection.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.core edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.core.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.core.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.feature edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.feature.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.feature.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.flow edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.flow.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.flow.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.instance edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.instance.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.instance.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.parsesupport edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.pluginsupport edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.properties edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.property edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.property.impl edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.property.predeclared edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.property.util edu.cmu.sei.aadl.model
edu.cmu.sei.aadl.model.util edu.cmu.sei.aadl.model
edu.cmu.sei.osate.ui edu.cmu.sei.osate.ui.actions
edu.cmu.sei.aadl.unparser edu.cmu.sei.aadl.unparser