122
7/1/2005 1 OSATE Plug-in Development Guide Peter H. Feiler ([email protected]) Aaron Greenhouse ([email protected]) Software Engineering Institute Carnegie Mellon University Pittsburgh PA 15213 June 2005 Check List: Spell check Take care of “to dos”, especially dangling citations Refs to Javadoc Consistent use of: “meta model” or “meta-model”

OSATE Plug-in Development Guide - aadl.info Guide 2005-06-16... · OSATE Plug-in Development Guide ... Aaron Greenhouse ([email protected]) Software Engineering Institute ... 3.8

  • Upload
    hacong

  • View
    222

  • Download
    0

Embed Size (px)

Citation preview

7/1/2005

1

OSATE Plug-in Development Guide Peter H. Feiler ([email protected])

Aaron Greenhouse ([email protected]) Software Engineering Institute

Carnegie Mellon University Pittsburgh PA 15213

June 2005

Check List:

• Spell check

• Take care of “to dos”, especially dangling citations

• Refs to Javadoc

• Consistent use of: “meta model” or “meta-model”

7/1/2005

2

Table of Content 1 Reader’s Notes ........................................................................................................ 5

1.1 Assumptions About Audience.......................................................................... 5 1.2 More Stuff Here............................................................................................... 5

2 Setting Up OSATE.................................................................................................. 5 2.1 Getting the Eclipse/OSATE Components......................................................... 6 2.2 Installing Eclipse/OSATE................................................................................ 7

2.2.1 Installing the OSATE SDK Archive......................................................... 7 2.2.2 Adding the Plug-ins Using Eclipse Update Sites ...................................... 7 2.2.3 Installing Eclipse and the Plug-ins Separately .......................................... 7 2.2.4 Uninstalling Eclipse/OSATE.................................................................... 8

2.3 Verify the Installation ...................................................................................... 8 3 A First Plug-in: Model Statistics.............................................................................. 9

3.1 Writing the Analysis Code............................................................................... 9 3.1.1 Creating an OSATE Plug-in Project ......................................................... 9 3.1.2 Setting the Plug-in’s Dependencies ........................................................ 11

3.2 Gathering Model Statistics............................................................................. 13 3.2.1 Subclassing AadlProcessingSwitch ........................................................ 14 3.2.2 The ModelStatistics Code ...................................................................... 15 3.2.3 An Alternative Use of Switches ............................................................. 18

3.3 Driving the Plug-in ........................................................................................ 19 3.3.1 Eclipse Actions ...................................................................................... 19 3.3.2 The Model Statistics Action Code .......................................................... 20

3.4 Creating an Icon for the Plug-in ..................................................................... 22 3.5 Describing the Action in the plugin.xml File.................................................. 23

3.5.1 The Complete plugin.xml File................................................................ 25 3.6 Executing the Model Statistics Plug-in........................................................... 26

3.6.1 Model Statistics in Action ...................................................................... 29 3.7 Deploying Model Statistics ............................................................................31 3.8 Summary of Concepts.................................................................................... 33

3.8.1 Eclipse ................................................................................................... 33 3.8.2 Meta Model ........................................................................................... 34 3.8.3 OSATE API........................................................................................... 35

4 Processing of AADL Models................................................................................. 35 4.1 Meta Model Defined AADL Models.............................................................. 35 4.2 Notes on Accessing Models ........................................................................... 37

4.2.1 An API for Accessing AADL Models .................................................... 37 4.2.2 Eliding Model Structure......................................................................... 38 4.2.3 AADL Inheritance Semantics................................................................. 39 4.2.4 Specialized Reference Associations........................................................ 40 4.2.5 Unifying “Either-Or” Associations......................................................... 41 4.2.6 Specific Instances of the Getter Method Patterns.................................... 41

4.3 AADL Model Traversal Support.................................................................... 44 4.3.1 Basic Traversal Support for AADL Model Processing ........................... 45 4.3.2 Traversal Methods ................................................................................. 48

7/1/2005

3

4.3.3 An Example: Priority Inversion Checking .............................................. 51 4.3.4 Meta-Model Class Based AADL Model Processing ............................... 52 4.3.5 Reporting Markers During a Traversal ................................................... 57

4.4 AADL Model Manipulation Support.............................................................. 57 5 Processing AADL Properties ................................................................................. 58

5.1 The Security Level Plug-in ............................................................................58 5.2 An Overview of AADL Properties ................................................................. 59

5.2.1 AADL Property Types ........................................................................... 59 5.2.2 AADL Property Declarations ................................................................. 62 5.2.3 Basic AADL Property Associations ....................................................... 63 5.2.4 The “SecurityLevel” Property ................................................................ 64 5.2.5 Property Lookup .................................................................................... 65

5.3 AADL Properties in the Meta Model ............................................................. 66 5.3.1 Properties and the Instance Model.......................................................... 70

5.4 Implementing the Security Level Plug-in ....................................................... 71 5.4.1 Getting the Property Declaration and Driving the Analysis..................... 71 5.4.2 Class ComponentSecuritySwitch............................................................ 73 5.4.3 Class ConnectionSecuritySwitch............................................................ 75

5.5 Getting Simple Property Values..................................................................... 76 5.6 Manipulating Property Values........................................................................ 77

5.6.1 Copying PropertyValues ........................................................................ 78 5.6.2 Unparsing Property Values..................................................................... 78 5.6.3 Using Range Values............................................................................... 79 5.6.4 Getting Type Literals ............................................................................. 79 5.6.5 Scaling Number Values.......................................................................... 79 5.6.6 Setting Number Values .......................................................................... 80

5.7 Advanced Property Associations.................................................................... 81 5.7.1 Modal Property Associations.................................................................. 81 5.7.2 Nonexistent Property Values.................................................................. 82 5.7.3 Modes and Property References ............................................................. 82

5.8 OSATE Properties API .................................................................................. 83 5.8.1 Using Predeclared Properties.................................................................. 83 5.8.2 More about AaxlReadOnlyAction.initPropertyReferences...................... 83 5.8.3 General Lookup of Property Sets, Definitions, Constants, and Types ..... 85 5.8.4 Testing “Applies to”............................................................................... 87 5.8.5 Getting Property Values ......................................................................... 87 5.8.6 Modifying Property Associations ........................................................... 90

6 Working with Flows.............................................................................................. 93 6.1 Flow Specifications and Flow Instances......................................................... 93

6.1.1 Flow Specification Declarations............................................................. 94 6.1.2 Flow Implementation Declarations......................................................... 94 6.1.3 End-To-End Flow Declarations.............................................................. 96 6.1.4 End-To-End Flow Instances ................................................................... 96 6.1.5 Textual Flow Declaration Examples....................................................... 97

6.2 Flows in the AADL Meta Model.................................................................... 98 6.2.1 Flow Specification Declarations............................................................. 98

7/1/2005

4

6.2.2 Flow Implementations and End-To-End-Flows .................................... 100 6.2.3 End-To-End Instance Flows ................................................................. 102

6.3 The Flow Analysis Plug-in........................................................................... 102 6.3.1 Meeting Flow Requirements ................................................................ 102 6.3.2 Handling of Missing Latency Properties............................................... 104 6.3.3 Propagation of Flow Latency Information ............................................ 105 6.3.4 Reusing the Analysis for Instance Models ............................................ 106

6.4 Specification-Based End-To-End Flow Analysis.......................................... 107 6.4.1 The Display System Model Scenario.................................................... 107 6.4.2 The Partition Latency Analysis ............................................................ 109 6.4.3 Partition Latency Analysis Refinement ................................................ 110

6.5 Latency Analysis with Instance Models ....................................................... 111 7 Writing Eclipse/OSATE Actions .........................................................................112 8 Managing the Results of an OSATE Plug-in........................................................ 112

8.1 Comparison of Result Management Mechanisms......................................... 112 8.1.1 Use of Eclipse Markers ........................................................................ 112 8.1.2 Use of SWT Dialog box ....................................................................... 112 8.1.3 Use of AADL Properties ...................................................................... 113 8.1.4 Use of Adapters on AADL Models ...................................................... 113 8.1.5 Use of the File System ......................................................................... 113 8.1.6 Use of Meta Model-Based XML Documents........................................ 113

9 Persistent Markers with AADL Models ............................................................... 114 9.1 OSATE Marker Types ................................................................................. 114

9.1.1 Defining New Marker Types................................................................ 114 9.2 Managing Markers with MarkerReporter ..................................................... 116

9.2.1 Reporting Markers ............................................................................... 117 9.2.2 Creating MarkerReporter Objects......................................................... 117 9.2.3 Limiting the Number of Markers.......................................................... 119 9.2.4 Deleting Markers ................................................................................. 119

9.3 Reporting Errors in the Plug-in .................................................................... 119 10 Packages Provided by the OSATE Plug-ins ..................................................... 121

7/1/2005

5

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?

2 Setting Up OSATE 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).

7/1/2005

6

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:

• 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 .

7/1/2005

7

• 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.

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 Site s 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 Separatel y 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.

7/1/2005

8

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 .

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.”

7/1/2005

9

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).

3 A First Plug-in: Model Statistics 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.

7/1/2005

10

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.statistics.

4. Click on “Next.”

5. Click on “Finish.”

7/1/2005

11

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.

• A plug-in manifest file, plugin.xml , that describes the appearance and structure of the plug-in. We will edit this file to declare the plug-in’s dependencies on other plug-ins as well as to define the toolbar button that is used to activate the plug-in’s action.

• A build.properties file that is used by Eclipse to influence how the plug-in in built. You generally do not have 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 already 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 in the EMF framework. The plug-in, therefore, also depends on the edu.cmu.sei.aadl.model plug-in and the org.eclipse.emf.ecore plug-in. In 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 10 “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 plugin.xml file:

1. Edit plugin.xml.

7/1/2005

12

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.

7/1/2005

13

Figure 6: Selecting a plug-in.

Alternatively, you can edit the XML directly by going to the “plugin.xml” pane. The dependencies are declared in the requires clause, e.g., <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"/> </requires>

3.2 Gathering Model Statistics To gather the model’s statistics, we 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. This class

• Provides model traversal methods (inherited from 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 our model statistics, we are going to create a new subclass, ModelStatistics, that defines our particular statistics gathering functionality. But first we must take a closer look at class AadlProcessingSwitch.

7/1/2005

14

3.2.1 Subclassing AadlProcessingSwitch The OSATE framework package edu.cmu.sei.aadl.model.util includes an abstract class ForAllAObject that defines methods for traversing AADL models but that leaves the method of processing abstract. Traversal methods include, for example, top-down and bottom-up traversals, as well as methods to process lists of model objects. The traversal methods can operate on both declarative and instance models; in the case of instance models, the traversal can be scoped to the full model or only a modal subset. The particular modal subset is determined by the system operational mode iteration mechanism (see xxx). The traversal methods abstract away the declarative/instance/modal distinctions by using the method AObject.getChildren, which encapsulates how the children of a model element are determined. Traversals invoke the processing method process(AObject). The default implementation of process implements functionality for filtering model elements via the suchThat method; see Section 4.3.1.1 “Default Processing of Visited Model Objects.”

Class AadlProcessingSwitch, also in edu.cmu.sei.aadl.model.util, is a subclass of ForAllAObject that overrides the process method to leverage the EMF “switch” class concept to define a processing method for all abstract and concrete classes in the AADL meta model (see EMF book page xxx). 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, and 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 Java 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 given a SystemType instance, doSwitch invokes the methods, caseSystemType, caseComponentType, caseSystemClassifier, caseComponentClassifier, caseClassifier, casePropertyHolder, caseNamedElement, caseAObject, and defaultCase, in order, until one of them returns a non-null value.

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.

7/1/2005

15

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 The class ModelStatistics extends AadlProcessingSwitch and declares 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 that it defines. To gather the statistics for a particular model, the analysis 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 class’s Javadoc which traversal method is expected to be used. Analysis results are retrieved using additional methods defined in ModelStatistics.

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. We later discuss an alternative implementation approach that avoids this testing inside of ComponentType.

7/1/2005

16

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]. In particular, 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.ComponentIns tance; import edu.cmu.sei.aadl.model.instance.ConnectionIn stance; import edu.cmu.sei.aadl.model.instance.util.Instanc eSwitch; import edu.cmu.sei.aadl.model.property.ComponentCat egory; import edu.cmu.sei.aadl.model.util.AadlProcessingSw itch; public class ModelStatistics extends AadlProcessing Switch { /* Counters to keep track of occurrences of diffe rent * 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(); } 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

7/1/2005

17

coreSwitch = new CoreSwitch() { /* We want to count all component type declar ations. * Thus, we count instances of the abstract C omponentType class. */ public Object caseComponentType(ComponentType obj) { typeCount++; // Only count those that are not DataType if (!(obj instanceof DataType)) componentTy peCount++; return DONE; } public Object caseComponentImpl(ComponentImpl ci) { compImplCount++; return DONE; } }; // We want to count flows, thus, we redefine th e FlowSwitch flowSwitch = new FlowSwitch() { public Object caseFlowSpec(FlowSpec obj) { flowCount++; return DONE; } public Object caseEndToEndFlow(EndToEndFlow o bj) { endToEndFlowCount++; return DONE; } }; // We want to count instance model objects. instanceSwitch = new InstanceSwitch() { public Object caseComponentInstance(Component Instance obj) { componentCount++; /* We want to count category specific insta nces. We retrieve * the category and branch on its numeric r epresentation. */ 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; } return DONE; } public Object caseConnectionInstance(Connecti onInstance ci) { connectionCount++; return DONE;

7/1/2005

18

} }; /* Note: we did not redefine processing of elem ents * from the features or components packages. */ } public String getModelResult() { return "Model Statistics: " + componentTypeCoun t + " component type declarations, " + compIm plCount + " 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: " + threadCou nt + " threads, " + processCount + " processes, " + connect ionCount + " semantic connections. "; } return null; } public String getExecutionPlatformResult() { if (componentCount > 0) { return "Execution platform statistics: " + pr ocessorCount + " processors, " + memoryCount + " memor y 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++; return DONE; } } componentSwitch = new ComponentSwitch() { public Object caseSystemType(SystemType obj) { componentTypeCount++; // We want to fall through to caseComponent Type return NOT_DONE;

7/1/2005

19

} public Object caseBusType(BusType obj) { componentTypeCount++; // We want to fall through to caseComponent Type return NOT_DONE; } // Repeat for all component types except Data Type };

We chose not to follow this implementation approach, however, 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.

• Perform the model traversal.

• Record/report the results.

To make an Eclipse action we need to create a new class that implements the action and to declare the action to Eclipse in the plugin.xml file. The model traversal will be invoked and the model results reported from a method in the new action class. Of particular importance is reporting the results of the analysis performed by the plug-in. We have several options for making the results available:

• 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.

• Store the result persistently as an AADL property in the model itself.

• Record the results temporarily with the model through an adapter.

• Store the results in a resource, i.e., file, in the Eclipse project workspace.

• Display the results in a dialog box.

In this example we will illustrate the first and last options. Section 8 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 the Eclipse interface org.eclipse.ui.IWorkbenchWindowActionDelegate. This class will execute our model statistics code.

2. Describing our action in the plug-in’s plugin.xml file.

7/1/2005

20

The interface IWorkbenchWindowActionDelegate declares methods that allow Eclipse to manage the lifecycle of the action. In particular, the method run(IAction) is invoked to actually execute the action. OSATE provides an abstract class AaxlReadOnlyAction, in package edu.cmu.sei.osate.ui.actions, that provides default implementations for all the action methods. The run implementation performs various sanity checks on the currently selected object and ensures that the necessary Eclipse resources are initialized before delegating to the abstract method doAaxlAction(AObject) , which is passed the selected model object. The intent is that to implement an action, the programmer needs only to extend AaxlReadOnlyAction and override the doAaxlAction method.

Class AaxlReadOnlyAction gets its name from the fact that any changes made to any models as a side effect of the action will not be saved. 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 either of these classes are triggered by first selecting an .aaxl file in the resource navigator or an AADL model element in an editor window, and then by executing the action by clicking on its icon in an Eclipse toolbar or by selecting the action’s menu item. When an .aaxl file is selected, doAaxlAction is passed the root element of the model contained in the file.

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,

7/1/2005

21

property set declarations, and package declarations in the workspace.1 If the 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. 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 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; import edu.cmu.sei.aadl.model.core.AObject; import edu.cmu.sei.aadl.model.instance.SystemInstan ce; import edu.cmu.sei.osate.ui.actions.AaxlReadOnlyAct ion; public class DoModelStatistics extends AaxlReadOnly Action { public void doAaxlAction(AObject obj) { // Get the root object of the model AObject root = obj.getAObjectRoot(); // Get the system instance (if any)

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.

7/1/2005

22

SystemInstance si = obj.getSystemInstance(); /* Create a new model statistics analysis objec t 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 worksp ace stats.processPreOrderAllDeclarativeModels(); // Analyze the instance model, if we have one if (si != null) { stats.processPreOrderAll(si); } /* Accumulate the results in a StringBuffer, bu t also report them * using info markers attached to the root mode l 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.getApplicationR esult(); final String epStats = stats.getExecutionPlat formResult(); reportInfo(root, appStats); reportInfo(root, epStats); msg.append(appStats); msg.append(epStats); } // Also report the results using a message dial og MessageDialog.openInformation( getShell(), "Model Statistics", msg.toStrin g()); } }

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 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.

7/1/2005

23

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 " 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">

7/1/2005

24

<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.DoModelStati stics.action" label="Model Statistics" tooltip="Compute model statistics" icon="icons/stats.gif" disabledIcon="icons/noStats.gif" class="edu.cmu.sei.osate.statistics.DoModelSt atistics" menubarPath="menu.analyses/top.grp" toolbarPath="statisticsDemo.toolbar" enablesFor="1"> <enablement> <or> <and> <objectClass name="org.eclipse.core.res ources.IFile"/> <objectState name="extension" value="aa xl"/> </and> <objectClass name="edu.cmu.sei.aadl.model. core.AObject"/> <objectClass name= "org.eclipse.emf.edit.provider.IWrapper ItemProvider"/> </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 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):

7/1/2005

25

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 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.StatisticsPl ugin"> <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.action Set" 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"

7/1/2005

26

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.reso urces.IFile"/> <objectState name="extension" value="aaxl"/> </and> <objectClass name="edu.cmu.sei.aadl.model.c ore.AObject"/> <objectClass name="org.eclipse.emf.edit.provider.IWr apperItemProvider"/> </or> </enablement> </action> </actionSet> </extension> </plugin>

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.”

7/1/2005

27

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.

Figure 9: The “Run” toolbar menu.

7/1/2005

28

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 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

7/1/2005

29

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.

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.

7/1/2005

30

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.

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.

7/1/2005

31

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.

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.)

7/1/2005

32

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 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.

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.

7/1/2005

33

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.

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

7/1/2005

34

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 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:

7/1/2005

35

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 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.

4 Processing of AADL Models 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

7/1/2005

36

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.

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.

7/1/2005

37

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

7/1/2005

38

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.

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.

7/1/2005

39

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 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

7/1/2005

40

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.

Figure 22: Portion of meta model showing the abstract “subcomponent” attribute between ComponentImpl and

Subcomponents.

7/1/2005

41

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 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 Patte rns

4.2.6.1 Package edu.cmu.sei.aadl.model.core Class Attribute Additional Methods

Abstract “features” getXAllFeature ComponentClassifier

Abstract “extends” getXExtend

ComponentImpl Abstract getXAllCallSequence

7/1/2005

42

Class Attribute Additional Methods getXCallSequence “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

getXSubcomponent(Mode)

Abstract “subcomponents”

getXSubcomponents

getXAllFeature

getXFeature Abstract “feature”

getXFeatures

getAllFlowSpec

ComponentType

“flowSpecs” getFlowSpec

getXAllDst Connection Abstract “dst”

getXDst

7/1/2005

43

Class Attribute Additional Methods getDstContext

“dstContext” getAllDstContext

Abstract “refines” getXRefines

getXAllSrc Abstract “src”

getXSrc

getSrcContext “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

4.2.6.3 Package edu.cmu.sei.aadl.model.flow Class Attribute Additional Methods

getXAllImplement FlowImpl Abstract “implement”

getXImplement

FlowSpec Abstract “dst” getXAllDst

7/1/2005

44

Class Attribute Additional Methods getXDst

getXAllDstContext Abstract “dstContext”

getXDstContext

getXAllSrc Abstract “src”

getXSrc

getXAllSrcContext 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 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.

7/1/2005

45

4.3.1 Basic Traversal Support for AADL Model Proces sing 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.

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 ForAllAObjec t() { 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

7/1/2005

46

• 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 m s 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).getNa me()); } };

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).getNa me()); } };

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);

7/1/2005

47

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).getNam e()); } };

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.

• 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((ComponentI nstance) obj1); double b = TimingUtil.getPeriodInUS((ComponentI nstance) obj2); if (a > b) return 1; if (a == b) return 0; return -1; } };

7/1/2005

48

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 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.

7/1/2005

49

The traversal follows the containment hierarchy of the declarative or instance model. In case of the AADL instance model the containment hierarchy corresponds to the system hierarchy. In case of the declarative AADL model the containment hierarchy does not reflect the system hierarchy nor a declaration/use hierarchy. Instead it represents the abstract syntax structure of an AADL specification.

• processPreOrderAll(AObject start): Traverses the containment hierarchy starting with the model object start and does so in prefix order. This means that the first child of an object and its children are visited before the second child is visited. This traversal method allows information to be propagated down the model hierarchy.

• processPostOrderAll(AObject start): Traverse the containment hierarchy using the model object start as starting point and does so in postfix order. This means that the children of an object are visited before the object itself. The start object is visited last. This traversal method allows information to be propagated up the model hierarchy.

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 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

7/1/2005

50

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 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.

7/1/2005

51

• processPreOrderAll(): Traverses the containment hierarchy over the whole OSATE workspace and does so in prefix order.

• processPostOrderAll(): Traverses the containment hierarchy over the whole OSATE workspace and does so in postfix order.

• processAllComponentImpl(): Processes all component implementations in the OSATE workspace.

• processTopDownComponentImpl(): Processes all component implementations in the OSATE workspace in the definition–use order.

• processBottomUpComponentImpl(): Processes all component implementations in the OSATE workspace in the inverse definition–use order.

• processPreOrderAllDeclarativeModels(): Traverses the component hierarchy of all declarative models in the OSATE workspace in prefix order.

• processPostOrderAllDeclarativeModels (): Traverses the component instance hierarchy of all declarative models in the OSATE workspace in postfix order.

• processPreOrderAllComponentInstances(): Traverses the component instance hierarchy of all instance models in the OSATE workspace in prefix order.

• processPostOrderAllComponentInstances(): Traverses the component instance hierarchy of all instance models in the OSATE workspace in postfix order.

4.3.3 An Example: Priority Inversion Checking We have included much of the implementation of a plug-in that checks for priority inversion of periodic threads assigned to the same processor, if they have manually assigned priorities.

The first method is applied to an AADL instance model by passing in a SystemInstance object as the root of the instance model. The method invokes the method checkPriorityInversion on every processor instance object. It does so by redefining the process method and by invoking the component instance traversal method for the component category of processor on the system instance as the root of the traversal.

An alternate implementation of this method public void checkSystemPriorityInversion(SystemIn stance 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(SystemIn stance si) {

7/1/2005

52

EList proclist = ForAllAObject.INSTANCE.processPreOrderCompon entInstance( si, ComponentCategory.PROCESSOR_LITERAL); for (Iterator it = proclist.iterator(); it.hasN ext();) { checkPriorityInversion((ComponentInstance) it .next()); } }

The second method generates a list of all threads that are bound to a specific processor, sorts the thread list with QuickSort according to their period (see Section 4.3.1.5.1 “QuickSort” above), and then checks the sorted list for increasing monotonicity of the priority across thread rate groups by calling on the method checkIncreasingMonotonicity. The threadlist is created by redefining suchThat to compare the value of the actual processor binding property of a thread to the current processor of the inversion analysis and invoking the component instance traversal for the category of thread. /** * check for priority inversion of thread bound to the given processor * @param curProcessor ComponentInstance of process or */ public void checkPriorityInversion(ComponentInstanc e curProcessor) { SystemInstance root = curProcessor.getSystemInsta nce(); // final makes currentProcessor accessible to the refined suchThat final ComponentInstance currentProcessor = curPro cessor; EList boundThreads = new ForAllAObject() { protected boolean suchThat(AObject obj) { ComponentInstance boundProcessor = TimingUtil.getActualProcessorBinding((Com ponentInstance)obj); return (boundProcessor == currentProcessor); } }.processPreOrderComponentInstance( root, ComponentCategory.THREAD_LITERAL); /* We will sort the thread list by period and che ck to make sure * the assigned priority is monotonically decreas ing. */ 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

7/1/2005

53

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.

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.

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

7/1/2005

54

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 AadlProcessing Switch { 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 o bj) { 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 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().

7/1/2005

55

// Get the system instance (if any) final SystemInstance si = obj.getSystemInstance (); /* Create a new model statistics analysis objec t. Run it over the * instance model if it exists. Otherwise, run it over all the * declarative models in the workspace. */ final ModelStatistics stats = new ModelStatisti cs(); 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 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

7/1/2005

56

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.hasNex t();) { 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.

• 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.

7/1/2005

57

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.

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.ge tMarkerReporter()); // ... } }

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:

7/1/2005

58

• 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.

• 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.

5 Processing AADL Properties 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.

7/1/2005

59

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 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_U nits; -- 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:

• The aadlboolean property type represents Boolean values and has two values: true and false. AADL supports Boolean arithmetic with aadlboolean values.

7/1/2005

60

• 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.

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.

7/1/2005

61

• 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:

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 (al l); referenceProp: ps::referenceType applies to (all) ; end ps; system Inner

7/1/2005

62

end Inner; system Outer end Outer; system implementation Outer.Impl subcomponents innerSubComponent: system Inner; properties ps::classifierProp => system Inner; ps::referenceProp => reference innerSubComponen t; 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: 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

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.

7/1/2005

63

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 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", "Helpe r.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.

7/1/2005

64

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 { 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 gr oup, process, memory, processor, bus, de vice, 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 prope rty value -- updated to be maximum of the subcomponent T1 and T2 values: 8 process implementation Proc.Impl subcomponents T1: thread Peter.Default;

7/1/2005

65

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 prop erty 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 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.

7/1/2005

66

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.”

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.

7/1/2005

67

Figure 27: Classes PropertyDeclaration and PropertyAssociation.

7/1/2005

68

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

7/1/2005

69

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 PropertyDefinition s; 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 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

7/1/2005

70

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 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.

7/1/2005

71

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.

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. 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.

7/1/2005

72

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

property set PropertyDefinition lookupPropertyDefinition( 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 = "Secu rityLevel"; private static final String SEI_PACKAGE = "SEI"; public static volatile PropertyDefinition securit yLevel = null; protected void initPropertyReferences() { // Initialize our one property reference securityLevel = lookupPropertyDefinition(SEI_PACKAGE, SECURIT YLEVEL);

7/1/2005

73

} public void doAaxlAction(AObject obj) { if (obj == null) return; final AObject as = obj.getAObjectRoot(); /* Ensure that enclosing component security lev el encompasses * contained security levels. */ if (as instanceof AadlSpec) { final ComponentSecuritySwitch componentSecuri tySwitch = new ComponentSecuritySwitch(getMarkerReport er()); // Walk up the component implementation refer ence hierarchy componentSecuritySwitch.processBottomUpCompon entImpl( (AadlSpec) as); // Check security along connections final ConnectionSecuritySwitch connectionSecu ritySwitch = new ConnectionSecuritySwitch(getMarkerRepor ter()); connectionSecuritySwitch.processPreOrderAll(a s); } } }

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

7/1/2005

74

PropertyHolder.setPropertyValue(PropertyDefinition, PropertyValue). This method is one of several property setting methods described in more detail in Section 5.8.6.1 “Setting Property Associations.” public class ComponentSecuritySwitch extends AadlPr ocessingSwitch { public ComponentSecuritySwitch(final MarkerReport er 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.s ecurityLevel); long cilv = 0; if (cipv instanceof IntegerValue) { cilv = ((IntegerValue) cipv).getValue(); } // Get the max security level of my subcomp onents long maxslv = 0; final EList subs = ci.getXAllSubcomponent() ; for (Iterator it = subs.iterator(); it.hasN ext();) { final Subcomponent sub = (Subcomponent) i t.next(); final ComponentImpl sci = sub.getComponen tImpl(); if (sci != null) { PropertyValue scipv = sci.getSimplePropertyValue(CheckSecur ity.securityLevel); if (scipv instanceof IntegerValue) { long slv = ((IntegerValue) scipv).get Value(); // Update max subcomponent security l evel if (slv > maxslv) maxslv = slv; } } } if (maxslv > cilv) { /* Subcomponents have higher security lev el 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 subc omponent 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.createInteger Value(); // Set to max security level newpv.setNewValue(maxslv); // Set the property association ci.setPropertyValue(CheckSecurity.securit yLevel, newpv); } return DONE; }

7/1/2005

75

}; } }

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 AadlP rocessingSwitch { public ConnectionSecuritySwitch(final MarkerRepor ter 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.getAllSrcC ontextComponent(); final PropertyHolder dcxt = conn.getAllDstC ontextComponent(); if (scxt == null || dcxt == null) return DO NE; // Get the security levels of the end point s 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, "Security level violation: Source has l evel " + slv + " and destination has level " + dlv); } return DONE;

7/1/2005

76

} }; } }

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.

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.

7/1/2005

77

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)

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

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. 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.

7/1/2005

78

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.getProp ertyValue(pd); if (iv != null) { IntegerValue iv2 = PropertyFactory.eINSTANCE.cr eateIntegerValue(); 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 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().

7/1/2005

79

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.

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.findPropertyTy pe( "Example", "English_Units"); final IntegerValue iv = (IntegerValue) ph.getSimplePropertyValue( "Example", "Documentation_Thic kness"); System.out.println("Scaled Value: " + iv.getScale dValue()); System.out.println("In Yards: " + iv.getScaledValue(units.findUnitLiteral("yard") ));

7/1/2005

80

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 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.findPropertyTy pe( "Example", "English_Units"); final IntegerValue iv2 = PropertyFactory.eINSTANCE.createIntegerValue(); iv2.setNewValue(18L); iv2.setUnitLiteral(units.findUnitLiteral("inch")) ; System.out.println("New value: " + iv2.getValueAs String()); System.out.println("valueString: " + iv2.getValue String()); System.out.println("Scaled Value: " + iv2.getScal edValue()); 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

7/1/2005

81

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.

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.

7/1/2005

82

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; system Example properties PS::bool3 => value(PS::bool1) and value(PS::boo l2); end Example; system implementation Example.Impl

6 Assuming that property PS::x does not have a default value.

7/1/2005

83

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.

5.8.2 More about AaxlReadOnlyAction.initPropertyRef erences 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

7/1/2005

84

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)

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.

7/1/2005

85

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 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.

7/1/2005

86

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.

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 EList getAllPropertyDefinition(

7/1/2005

87

global—declared in the given context 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.”

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 ????.

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.”

7/1/2005

88

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.

• 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().

• Method PropertyValue getScalarValue() returns the value if !isList() . The method throws an UnsupportedOperationException if isList().

7/1/2005

89

• 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("P S", "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()) { (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

7/1/2005

90

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 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.

7/1/2005

91

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 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.

7/1/2005

92

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)

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)

7/1/2005

93

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)

6 Working with Flows 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 in terms of end-to-end latency from sensor to actuator to reflect the latency assumption embedded in its extrapolation algorithm.

7/1/2005

94

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 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.

7/1/2005

95

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 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.

7/1/2005

96

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 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

7/1/2005

97

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.

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 i ts 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;

7/1/2005

98

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.fs ink; -- a flow source may start in a subcomponent, -- i.e., the first named element is a flow sourc e 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 n ot 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

7/1/2005

99

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 case, the port group is referenced as the context (srcContext or dstContext) of the source (“src”) or destination (“dst”) reference.

7/1/2005

100

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.

7/1/2005

101

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.

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).

7/1/2005

102

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. 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:

7/1/2005

103

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 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();

7/1/2005

104

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.getSimp lePropertyValue( PredeclaredProperties.LATENCY); if (cpv != null) { result = result + cpv.getScaledValue(PredeclaredProperties. MICROSEC); } } else { FlowSpec fefs = fe.getFlowSpec(); if (fefs != null){ IntegerValue fefspv = (IntegerValue) fefs.getSimplePropertyValu e( PredeclaredProperties.LATENCY); if (fefspv != null) { result = result + fefspv.getScaledValue(PredeclaredProper ties.MICROSEC); } else { // handle the case when no latency is spe cified } } // store the result as flow implementation late ncy IntegerValue newpv = PropertyFactory.eINSTANCE.createIntegerValue( ); newpv.setNewValue((long) result); newpv.setUnitLiteral(PredeclaredProperties.MICR OSEC); fi.setPropertyValue(PredeclaredProperties.LATEN CY,newpv); // now we compare the result to the latency in the flow spec IntegerValue fspv = (IntegerValue) fs.getSimple PropertyValue( PredeclaredProperties.LATENCY); if (fspv != null) { double fslv = fspv.getScaledValue( PredeclaredProperties.MICROSEC); if (result > fslv) { reportError(fi, "Flow implementation latenc y " + result + "exceeds flow spec latency " + f slv); } }

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.

7/1/2005

105

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.getSimpl ePropertyValue( 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 { Subcomponent sc = fe.getFlowContext(); if (sc instanceof ThreadSubcomponent){ ThreadClassifier tc = ((ThreadSubcomponent) sc) .getClassifier(); EnumLiteral dp = tc.getDispatchProtocol(); if (dp == PredeclaredProperties.PERIODIC && was DelayedConnection) { IntegerValue period = (IntegerValue) sc.getSi mplePropertyValue( PredeclaredProperties.PERIOD); if (period != null){ result = result + period.getScaledValue(PredeclaredProperti es.MICROSEC); } else { reportInfo(sc, "Thread subcomponent has no flowspec latency " + "or periodic thread period"); } } else { IntegerValue deadline = (IntegerValue) sc.get SimplePropertyValue( 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().getCategor y().getName() + " subcomponent has no flowspec latency for fl ow " + 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

7/1/2005

106

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.cr eateIntegerValue(); newpv.setNewValue((long)result); newpv.setUnitLiteral(PredeclaredProperties.MICROS EC); fi.setPropertyValue(PredeclaredProperties.LATENCY ,newpv); // now we compare the result to the latency in th e flow spec IntegerValue fspv = (IntegerValue)fs.getSimplePro pertyValue( PredeclaredProperties.LATENCY); if (fspv != null){ public Object caseComponentImpl(ComponentImpl c i) { self.processEList(ci.getFlowSequence()); // alternative: self.processPreOrderAll(ci); return DONE; } public void doAaxlAction(AObject obj){ AObject root = obj.getAObjectRoot(); AadlProcessingSwitch flowLatencySwitch = new FlowLatencyAnalysisSwitch(getMarkerReport er()); if (root instanceof AadlSpec) { flowLatencySwitch.processBottomUpComponentImp l((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(getMarkerReport er()); if (root instanceof AadlSpec){ flowLatencySwitch.processBottomUpComponentImp l((AadlSpec)root); } else { flowLatencySwitch.processPreOrderComponentIns tance( (SystemInstance) root); }

7/1/2005

107

reportDone(root,"Flow Latency Checking"); } public Object caseComponentInstance(ComponentInst ance ci) { Subcomponent sub = ci.getSubcomponent(); ComponentImpl cii = sub.getComponentImpl(); if (cii == null) return DONE; self.processPreOrderAll(cii); return DONE; } public Object caseSystemInstance(SystemInstance c i) { SystemImpl si = ci.getSystemImpl(); self.processPreOrderAll(si); return DONE; }

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.

7/1/2005

108

Figure 40: A Subsystem End-To-End Flow

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_Cm d_Pushed -> Pilot_DM.Menu_selection_from_Display; menu_cmd_to_PCM: event data port Pilot_DM.New_P age_Request_To_PCM -> PCM.New_Page_Request_From_DM; menu_cmd_to_FM: event data port PCM.New_Page_Re quest_To_FM -> FM.New_Page_Request_From_PCM; menu_cmd_to_FD: event data port FM.New_Page_Req uest_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_Conten t_To_PCM -> PCM.New_Page_Content_from_FM; page_to_DM: event data port PCM.New_Page_Conten t_To_DM -> Pilot_DM.New_Page_Content_from_PCM; page_to_Display: data port Pilot_DM.New_Page_Im age_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

7/1/2005

109

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 ( sys tem ); end SEI;

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.getSi mplePropertyValue( PredeclaredProperties.LATENCY); double latency = 0; if (fefspv != null) { result = fefspv.getScaledValue(PredeclaredPro perties.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).getScaled Value( PredeclaredProperties.MICROSEC); result = result + partlatency; } else { reportInfo(sc, sc.getComponentType().getCat egory().getName() + " subcomponent has no partiton latency"); } }

7/1/2005

110

}

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_La tency"); }

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(PredeclaredProperti es.LATENCY); if (epv == null) { epv = etef.getSimplePropertyValue( PredeclaredProperties.EXPECTED_LATENCY); } if (epv != null) { double val = ((IntegerValue) epv).getScaledValu e( PredeclaredProperties.MICROSEC); reportInfo(etef,"Expected end-to-end flow laten cy 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 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.

7/1/2005

111

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.getSimplePropertyVal ue( PredeclaredProperties.LATENCY); if (cpv != null) { double val = ((IntegerValue) cpv).getScaled Value( PredeclaredProperties.MICROSEC); prevlatency = prevlatency + val; } } } else { sc = fe.getFlowContext(); pl = (IntegerValue) sc.getSimplePropertyValue( CheckFlowLatency.partitionLatency); partlatency = 0; if (pl != null) { partlatency = ((IntegerValue) pl).getScaledVa lue( PredeclaredProperties.MICROSEC); result = result + (partlatency >= prevlatency ? partlatency : (partlatency == 0 ? prevlatency : (((int) prevlatency/partlatency) + 1) * partlatency)); } else { reportInfo(sc, sc.getComponentType().getCateg ory().getName() + " subcomponent has no partiton latency"); } fefs = fe.getFlowSpec(); fefspv = (IntegerValue) fefs.getSimplePropertyV alue( PredeclaredProperties.LATENCY); latency = 0; if (fefspv != null) { latency = fefspv.getScaledValue(PredeclaredPr operties.MICROSEC); } if (partlatency != 0) { prevlatency = (latency > partlatency) ? laten cy : partlatency; } else { prevlatency = prevlatency + ((latency > partlatency) ? latency : partla tency); } } } /* 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

7/1/2005

112

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.

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.

8 Managing the Results of an OSATE Plug-in 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.

7/1/2005

113

• 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

• 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

7/1/2005

114

• This method is used to generate the AADL instance model

9 Persistent Markers with AADL Models 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 3 “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

7/1/2005

115

id="ModelStatisticsObjectMarker" name="Model Statistics Marker" point="org.eclipse.core.resources.markers" > <super type="edu.cmu.sei.aadl.model.AadlObjec tMarker"/> <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, 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.

7/1/2005

116

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 MarkerReporter , we describe how to use a MarkerReporter before describing how to create new instances of MarkerReporter .

7/1/2005

117

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 AaxlReadOnlyAc tion { // ... public void doAaxlAction(AObject obj) { // ... SystemImpl si = (SystemImpl) obj; InstantiateModel instantiateModel = new InstantiateModel(getMarkerReporter()); instantiateModel.buildInstanceModelFile(si); if (getMarkerReporter().externalErrors() > 0) { MessageDialog.openWarning(getShell(), "Instan tiation Warning", "The instantiated model may have errors o r warnings. " + "Please select the generated instance mod el 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 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

7/1/2005

118

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 AaxlReadOnly Action { private static final String MARKER_TYPE = "edu.cmu.sei.osate.statistics.ModelStatisticsOb jectMarker"; public String getMarkerType() { return MARKER_TYPE; } // ... }

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 AaxlReadOnlyActi on { private final String PASS1_MARKER_TYPE = ...; private final String PASS2_MARKER_TYPE = ...; public String getMarkerType() { return PASS1_MARKER_TYPE;

7/1/2005

119

} 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 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

7/1/2005

120

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 e rror 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.

Figure 43: "Error Log" entries after executing example code.

7/1/2005

121

Figure 44: Viewing the details of an error log entry.

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

7/1/2005

122

Java Package OSATE Plug-in 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