osate plug-in development guideaadl.sei.cmu.edu/aadlinfosite/linkeddocuments/plug-in guide...

149
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

Upload: dangtram

Post on 27-Mar-2018

223 views

Category:

Documents


1 download

TRANSCRIPT

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

84

Figure 28: Classes for representing non-Boolean property values.

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