• No results found

Towards more robust advice : message flow analysis for composition Filters and its Application

N/A
N/A
Protected

Academic year: 2021

Share "Towards more robust advice : message flow analysis for composition Filters and its Application"

Copied!
253
0
0

Bezig met laden.... (Bekijk nu de volledige tekst)

Hele tekst

(1)

Towards More Robust Advice:

Message Flow Analysis for Composition Filters and its Application

A thesis submitted for the degree of Master of Science at the University of Twente

A.J. de Roo

Enschede, March 29, 2007

Graduation committee:

Prof. dr. ir. M. Ak¸sit Dr. ir. L.M.J. Bergmans Ir. P.E.A. D¨urr

Ir. T. Staijen

Twente Research and Education on Software Engineering Department of Computer Science Faculty of Electrical Engineering, Mathematics and Computer Science University of Twente

(2)
(3)

Abstract

Aspect oriented programming improves the quality of software by allowing a better separation of concerns. Composition filters is a delegation based AOP approach. It introduces advice by filtering messages sent between objects.

The declarative syntax of composition filters opens possibilities for powerful reasoning about the behavior of a set of filters. This reasoning includes control flow analysis. But control flow analysis is only the basis of a much more powerful reasoning technique, called message flow analysis. Message flow analysis reasons about the behavior of a filter set for a specific message. It is a combination of control flow analysis and data flow analysis on the message entity.

Message flow analysis brings opportunities for powerful conflict detection techniques, analyzing concern signature modifications, inlining of a set of filters and more.

This thesis presents a new approach to message flow analysis, called the message flow simulation approach. This new approach improves upon existing approaches, like the message-action tree approach, by providing better granularity, traceability and efficiency.

This thesis also works out four different applications of filter reasoning. First, it explains how consistency reasoning can do better reachability analysis and how the results from message flow analysis are used to create a cause and effect relationship between consistency conflicts. Second, it explains how message flow analysis is used to analyze signature modification. Third, it explains how message flow analysis makes behavioral reasoning more precise and more efficient. Finally, it explains how message flow analysis is used to translate a filter set to executable code, which can be woven in the base program.

(4)
(5)

Acknowledgements

With the finishing of my thesis my graduation project has come to an end. There are a number of people that supported me during my graduation project, for which I am grateful.

First, I would like to thank the members of my graduation committee. I would like to thank Lodewijk Bergmans, my supervisor, for being an example of a true scientist to me. With his always critic eye and expert knowledge he was of great guidance to me. I also would like to thank Pascal D¨urr. He inspired me with his never ending enthusiasm about composition filters and all its facets. I would like to thank him for always being available for answering questions, giving advice and enlightening discussions. Next, I would like to thank Tom Staijen. Although a less prominent member of my committee, his initial work on this subject gave me a good start of my graduation project.

Next, I would like to thank Michiel van Oudheusen and Sverre Boschman for the enjoyable time we had together during the StarLight project and all other Compose?

developers for their valuable input.

Last, but not least, I would like to thank my parents and my sister for their love and support during all those years and for their unconditional faith in me.

Arjan de Roo March 29, 2007 Enschede, The Netherlands

(6)
(7)

Contents

Abstract i

Acknowledgements iii

I Introduction 1

1 Introduction to AOSD 2

1.1 Introduction . . . . 2

1.2 Traditional Approach . . . . 4

1.3 AOP Approach . . . . 5

1.3.1 AOP Composition . . . . 6

1.3.2 Aspect Weaving . . . . 6

1.4 AOP Solutions . . . . 8

1.4.1 AspectJ Approach . . . . 9

1.4.2 Hyperspaces Approach . . . . 10

1.4.3 Composition Filters . . . . 11

2 Compose? 13 2.1 Evolution of Composition Filters . . . . 13

2.2 Composition Filters in Compose?. . . . 14

2.3 Demonstrating Example . . . . 16

2.3.1 Initial Object-Oriented Design . . . . 17

2.3.2 Completing the Pacman Example . . . . 17

2.4 Compose?Architecture . . . . 22

2.4.1 Integrated Development Environment . . . . 22

2.4.2 Compile Time . . . . 22

2.4.3 Adaptation . . . . 22

2.4.4 Runtime . . . . 22

2.5 Platforms . . . . 23

2.6 Features Specific to Compose? . . . . 23

2.7 StarLight . . . . 24

2.7.1 StarLight Architecture . . . . 25

2.7.2 Explicit Modeling of the Returning Flow . . . . 25

2.7.3 Defining New Filter Types and Filter Actions . . . . 27

2.7.4 Conditional Superimposition . . . . 29

(8)

3.1 Introduction . . . . 30

3.2 Architecture of the .NET Framework . . . . 31

3.2.1 Version 2.0 of .NET . . . . 32

3.3 Common Language Runtime . . . . 33

3.3.1 Java VM vs .NET CLR . . . . 34

3.4 Common Language Infrastructure . . . . 34

3.5 Framework Class Library . . . . 36

3.6 Common Intermediate Language . . . . 37

II Message Flow Analysis 40 4 Motivation 41 4.1 The Purpose of Filter Reasoning . . . . 41

4.1.1 Conflict Analysis and Error Detection . . . . 42

4.1.2 Signature Generation . . . . 43

4.1.3 Filter Inlining . . . . 45

4.1.4 Further Applicability . . . . 46

4.2 Problem Description . . . . 46

4.3 Requirements . . . . 46

4.3.1 Conceptual Requirements . . . . 47

4.4 Existing Approaches . . . . 48

4.4.1 Logical Expressions Approach . . . . 48

4.4.2 Message-Action Tree Approach . . . . 50

5 The Message Flow Simulation Approach 52 5.1 Transforming the Abstract Syntax Tree to a Flowchart . . . . 52

5.1.1 Transformation Rules . . . . 54

5.2 Simulating the Execution of a Message in the Filter Set . . . . 59

5.2.1 Adding a Frame . . . . 59

5.2.2 Execution Steps . . . . 60

5.2.3 Maintaining State . . . . 63

5.3 Simulating with each Possible Message . . . . 64

5.3.1 Different Messages that Behave the Same . . . . 64

5.3.2 Identifying Equivalence Classes . . . . 65

5.3.3 State Space Example . . . . 67

5.4 Computational Complexity . . . . 68

5.4.1 From AST to Flowchart . . . . 68

5.4.2 Simulating the Execution . . . . 72

5.4.3 Total Time Complexity . . . . 73

5.5 Discussion . . . . 74

5.5.1 Evaluating Condition Expressions . . . . 74

5.5.2 The Meta Filter Uncertainty . . . . 76

5.5.3 Target Matching . . . . 77

5.5.4 Message Lists . . . . 78

(9)

6 The Filter Reasoning Engine 80

6.1 Filter Reasoning Engine Overview . . . . 80

6.2 Using Graphs and Graph Transformations . . . . 81

6.2.1 Transforming the AST to a Flowchart . . . . 82

6.2.2 Simulating the Flowchart . . . . 82

6.2.3 Advantages and Disadvantages of using GROOVE . . . . 83

6.3 The Filter Reasoning Engine Preprocessor . . . . 83

6.3.1 Overview of the process . . . . 84

6.3.2 Class Structure . . . . 85

6.3.3 Preprocessing each filter module? . . . . 85

6.4 Combining the Information of Different Filter Modules in a Filter Set . . 87

6.4.1 Combining Different Flowcharts . . . . 87

6.4.2 Combining Different Execution Models . . . . 88

6.5 The Filter Reasoning Model . . . . 93

6.5.1 The FIRE Model Structure . . . . 93

6.5.2 The Flowchart Structure . . . . 94

6.5.3 The Execution Model Structure . . . . 96

6.6 Filter Reasoning Engine Tools . . . . 97

6.6.1 Iterators . . . . 98

6.6.2 Regular Expression Checker . . . . 98

6.6.3 Query Engine . . . . 98

6.6.4 Viewer . . . 101

6.7 Implementation issues . . . 101

6.7.1 Is Execution Model Expansion Needed? . . . 101

6.7.2 GROOVE’s inefficiency . . . 103

III Message Flow Analysis Applied 107 7 Consistency Reasoning 108 7.1 Theory and Concepts . . . 109

7.1.1 Identifying Unreachable Components . . . 109

7.1.2 From Unreachable Component to Conflict . . . 110

7.1.3 Computational Complexity . . . 115

7.2 Design and Implementation . . . 117

7.2.1 Position in the Compose?Architecture . . . 117

7.2.2 Structure of the Consistency Reasoning Engine . . . 117

7.2.3 Implementation of the Consistency Reasoning Algorithm . . . 118

7.2.4 Reporting Conflicts . . . 120

8 Signature Generation 122 8.1 Theory and Concepts . . . 122

8.1.1 Old Approach to Signature Generation and Type Checking . . . . 123

8.1.2 A Different Interpretation of Holljen’s Definition . . . 124

8.1.3 Representing the Signature Mapping as a Dependency Graph . . . 125

8.1.4 Using the Dependency Graph to Generate the Signatures . . . 128

(10)

8.1.6 Using Other Filter Actions as Sufficient Requirement for Inclusion

in the Signature . . . 139

8.2 From Theory to Practice . . . 140

8.2.1 Incrementally Building a Sufficient Subset of the Dependency Graph140 8.2.2 Initialization . . . 141

8.2.3 Start Signatures . . . 141

8.2.4 Final Signatures . . . 154

8.2.5 Type Checking and Conflict Detection . . . 156

8.2.6 Using Other Filter Actions as Sufficient Requirement for Inclusion in the Signature . . . 160

8.3 Design and Implementation . . . 163

8.3.1 Location in the Compilation Process . . . 163

8.3.2 Class Structure of the Signature Generation Engine . . . 163

9 Behavioral Reasoning 166 9.1 Theory and Concepts . . . 166

9.1.1 Introduction to Behavioral Reasoning . . . 167

9.1.2 Using Filter Reasoning for Behavioral Reasoning . . . 167

9.1.3 An Algorithm with Polynomial Time Complexity . . . 168

9.2 Design and Implementation . . . 173

9.2.1 Implemented Regular Expression Language . . . 173

9.2.2 Class Structure of the Regular Expression Matcher . . . 175

9.2.3 Implementation Details . . . 178

9.2.4 Integration with the Behavioral Reasoning Engine . . . 181

10 Filter Inlining 185 10.1 Theory and Concepts . . . 185

10.1.1 Flow Based Inlining . . . 186

10.1.2 Condition Based Inlining . . . 190

10.1.3 Flow Based Inlining with Jump Instructions . . . 193

10.1.4 Flow Based Inlining with Message Conditions . . . 194

10.1.5 Incorporating Conditional Superimposition . . . 195

10.1.6 Weaving Input Filters . . . 197

10.1.7 Weaving Output Filters . . . 201

10.2 Design and Implementation . . . 202

10.2.1 Overview of the Inlining Process . . . 202

10.2.2 The Abstract Instruction Model . . . 202

10.2.3 The Inlining Engine and Model Builder . . . 204

10.2.4 The Emitter: Communication from Java to .NET . . . 205

10.2.5 Weaving the Abstract Instruction Model into Common Interme- diate Language Assemblies . . . 208

10.2.6 Filter Inlining vs Runtime . . . 213

10.2.7 Inlining problems . . . 214

(11)

IV Conclusion 216

11 Conclusion 217

11.1 Discussion . . . 217

11.1.1 Message Flow Analysis . . . 217

11.1.2 Consistency Reasoning . . . 218

11.1.3 Signature Generation . . . 218

11.1.4 Behavioral Reasoning . . . 219

11.1.5 Filter Inlining . . . 219

11.2 Related Work . . . 220

11.2.1 Message Flow Analysis . . . 220

11.2.2 Consistency Reasoning . . . 220

11.2.3 Signature Generation . . . 221

11.2.4 Behavioral Reasoning . . . 221

11.2.5 Filter Inlining . . . 221

11.3 Future Work . . . 222

11.3.1 Message Flow Analysis . . . 222

11.3.2 Consistency Reasoning . . . 222

11.3.3 Signature Generation . . . 223

11.3.4 Behavioral Reasoning . . . 223

11.3.5 Filter Inlining . . . 223

11.4 Contributions . . . 224

11.4.1 Message Flow Analysis . . . 224

11.4.2 Consistency Reasoning . . . 224

11.4.3 Signature Generation . . . 224

11.4.4 Behavioral Reasoning . . . 225

11.4.5 Filter Inlining . . . 225

V Appendices 226 A Motivation Example 227 A.1 Base system . . . 227

A.2 LogMail Concern . . . 228

A.3 BufferMail Concern . . . 228

A.4 SecureConnection Concern . . . 229

(12)

List of Figures

1.1 Dates and ancestry of several important languages . . . . 3

2.1 Components of the composition filters model . . . . 15

2.2 Class diagram of the object-oriented Pacman game . . . . 18

2.3 Overview of the Compose?architecture . . . . 21

2.4 Explicit modeling of the returning flow . . . . 26

2.5 Filter actions can either continue, return or exit . . . . 26

3.1 Context of the .NET framework . . . . 32

3.2 Relationships in the CTS . . . . 35

3.3 Main components of the CLI and their relationships . . . . 36

3.4 From source code to machine code . . . . 37

4.1 Structure of the mail system example . . . . 42

4.2 New signature of Connection. . . . 44

4.3 The message-action tree . . . . 50

5.1 Example of an abstract syntax tree . . . . 53

5.2 Example of a flowchart . . . . 54

5.3 The Transformation rules . . . . 55

5.3 The Transformation rules (Continued) . . . . 56

5.3 The Transformation rules (Continued) . . . . 57

5.3 The Transformation rules (Continued) . . . . 58

5.3 The Transformation rules (Continued) . . . . 58

5.4 A frame element is used to simulate the execution . . . . 59

5.5 Doing an execution step . . . . 60

5.6 Branching execution steps . . . . 61

5.7 Handling the substitution part . . . . 62

5.8 Creating a state space during the simulation . . . . 63

5.9 Example of a state space . . . . 69

5.10 Execution model with an exponential number of states . . . . 79

6.1 Components in the Filter Reasoning Engine . . . . 80

6.2 The FIRE preprocessing process . . . . 84

6.3 Class structure of the FIRE Preprocessor . . . . 86

6.4 The flowchart of a filter module . . . . 87

6.5 First step: adding the filter module condition . . . . 88

(13)

6.6 Combining two flowcharts . . . . 89

6.7 The execution models corresponding to the separate filter modules . . . . 90

6.8 Adding filter module conditions to the execution model . . . . 90

6.9 Extended execution model of the first filter module . . . . 92

6.10 The execution models corresponding to the separate filter modules . . . . 93

6.11 Combined execution model . . . . 94

6.12 The FireModelcomponent . . . . 95

6.13 The Flowchartstructure . . . . 96

6.14 The ExecutionModelstructure . . . . 97

6.15 The Iteratorcomponents . . . . 98

6.16 The QueryEnginecomponents . . . . 99

6.17 The internal structure of the CTLQueryEngine . . . 100

6.18 The Viewercomponents . . . 101

6.19 The execution models corresponding to the separate filter modules . . . . 102

6.20 The combined execution model with and without expansion . . . 102

6.21 Time GROOVE took to do the transformation and simulation for varying sizes of filter sets on a linear scale . . . 104

6.22 Time GROOVE took to do the transformation and simulation for varying sizes of filter sets on a logarithmic scale . . . 105

6.23 Time the FIRE Model took to combine the results of different filter mod- ules in a filter set . . . 106

7.1 Finding unreachable nodes and edges by relating the states and transitions in the execution model back to the flowchart . . . 110

7.2 The cause and effect relation between conflicts . . . 115

7.3 CORE class diagram . . . 117

7.4 Sequence diagram showing how reachable components are found . . . 118

7.5 Sequence diagram showing how unreachable components are identified and checked for conflicts . . . 119

8.1 Partial representation of the dependency graph . . . 128

8.2 The existence of methods resolved in the dependency graph . . . 131

8.3 Cyclic dependency in the dependency graph . . . 133

8.4 An Unknownmethod node does not need to be in the dependency cycle . . 133

8.5 Example of a cyclic dispatch conflict . . . 136

8.6 Example of an infinite signature conflict . . . 137

8.7 Example of a dependency graph with a type error . . . 138

8.8 The rules to create the signature/type set . . . 143

8.9 Class structure of the signature generation engine . . . 163

9.1 Schematic representation of the flowchart . . . 168

9.2 Regular expression matcher public structure . . . 175

9.3 Regular expression matcher internal structure . . . 177

9.4 Schematic representation of the automaton corresponding to regular ex- pression e1 . . . 178

9.5 A single word regular expression . . . 179

9.6 Concatenation of e1 and e2 . . . 179

(14)

1 2

9.8 Kleene star operator on e1 . . . 180

9.9 Sequence diagram of SECRET’s original analysis phase . . . 182

9.10 Sequence diagram of SECRET’s new analysis phase . . . 182

9.11 Regular expression matcher integrated with SECRET . . . 183

10.1 Dividing the state space into filter blocks . . . 186

10.2 Dividing a filter block into filter element blocks . . . 187

10.3 States within a filter element block . . . 188

10.4 Substitution breaks sequential flow . . . 190

10.5 The condition based inlining rules . . . 191

10.6 Substitution leads to parallel flow traces through the filter set . . . 193

10.7 Generate code layer by layer to ensure the correct execution order . . . . 195

10.8 Dividing the state space into filter blocks and conditional superimposition states . . . 196

10.9 Approach 1: Using method wrapping to weave input filters . . . 198

10.10Overriding can lead to problems with method wrapping . . . 199

10.11Approach 2: Inserting filter code at the beginning of the method body . . 199

10.12Overriding can lead to problems in the inner call context if only a Boolean value is used . . . 200

10.13Output filter code replaces the original call . . . 201

10.14An overview of the inlining process . . . 202

10.15The abstract instruction model . . . 203

10.16Structure of the inlining engine and the model builder . . . 204

10.17FilterCode structure attached to the method or call . . . 205

10.18The weave specification object model . . . 206

(15)

Listings

1.1 Modeling addition, display, and logging without using aspects . . . . 4

1.2 Modeling addition, display, and logging with aspects . . . . 6

1.3 Example of dynamic crosscutting in AspectJ . . . . 9

1.4 Example of static crosscutting in AspectJ . . . . 10

1.5 Creation of a hyperspace . . . . 11

1.6 Specification of concern mappings . . . . 11

1.7 Defining a hypermodule . . . . 12

2.1 Abstract concern template . . . . 14

2.2 DynamicScoringconcern in Compose? . . . . 19

2.3 Implementation of classScore . . . . 20

2.4 DynamicStrategyconcern in Compose? . . . . 21

2.5 Defining theLoggingInfilter actions . . . . 27

2.6 Defining theLogging filter type . . . . 27

2.7 Conditional superimposition example . . . . 29

3.1 Adding example in IL code . . . . 38

3.2 Adding example in the C# language . . . . 39

3.3 Adding example in the VB.NET language . . . . 39

4.1 The LogMailconcern . . . . 42

4.2 The BufferMailconcern . . . . 42

4.3 The superimposed filter set . . . . 43

4.4 The SecureConnectionconcern . . . . 44

4.5 Inlining ofsend with pure control flow analysis . . . . 45

4.6 Inlining ofsend with message specific analysis . . . . 45

4.7 Message-action tree example . . . . 50

5.1 Example of a filter set . . . . 52

5.2 Example of same flow behavior, but different external behavior . . . . 65

5.3 Example of same external behavior, but different flow behavior . . . . 65

5.4 Example leading to pseudo-equivalence classes . . . . 67

5.5 Not taking conditions into account leads to more execution paths . . . . . 74

5.6 A more elaborate example of how not taking conditions into account leads to more execution paths . . . . 74

5.7 An example of aMetaaction changing a message by using aSubstitution filter . . . . 77

5.8 An example of how instance matching leads to the acceptance of a match- ing part . . . . 77

(16)

of states . . . . 78

6.1 The filter modules . . . . 88

7.1 Consistency conflicts example . . . 108

7.2 Consistency reasoning complete output . . . 120

7.3 Consistency reasoning primary conflict output . . . 120

7.4 Consistency reasoning leaf conflict + root cause . . . 120

7.5 Consistency reasoning level output . . . 121

8.1 Example of the incomplete signature problem . . . 124

8.2 Example of a type problem . . . 124

8.3 Example to illustrate the dependency graph concept . . . 127

8.4 Example of a cyclic dependency conflict . . . 132

8.5 Example leading to an infinite cyclic dependency conflict set . . . 134

8.6 Example leading to a type finite cyclic dependency conflict set . . . 134

8.7 Example of a paradoxical cyclic dependency conflict . . . 135

8.8 Example of a cyclic dispatch conflict . . . 136

8.9 Example of an infinite signature conflict . . . 137

8.10 Example of a concern with type errors . . . 138

8.11 Example to illustrate why a selector is added to the distinguishable set of the target concern . . . 146

9.1 Example of a filter set with exponentially many execution paths . . . 168

9.2 The regular expression grammar in EBNF . . . 173

10.1 Generating code for filter blocks . . . 187

10.2 Generating code for filter element blocks that might accept as well as reject189 10.3 Generating code for filter element blocks that always accept . . . 189

10.4 Generating code for filter element blocks that always rejects . . . 189

10.5 filter set leading to large condition expressions . . . 192

10.6 Generated code . . . 192

10.7 Using jump instructions to jump between parallel filter flows . . . 193

10.8 Using message conditions to select between parallel filter flows . . . 194

10.9 Generate code layer by layer to ensure the correct execution order . . . . 195

10.10Generating code for aFilterModuleCondition state . . . 196

10.11Example with conditional superimposition . . . 197

10.12Using filter context to cope with inner calls . . . 199

10.13Setting the inner call context . . . 200

10.14IL structure of the Branch instruction . . . 210

10.15Executing actions on return . . . 212

10.16Executing actions on return . . . 212

10.17Filter module used for the performance measurements . . . 213

11.1 Filter set that leads to a reachability conflicts in the second filter . . . 222

A.1 TheMailSystem class . . . 227

A.2 TheConnection class . . . 227

A.3 TheLogMailconcern . . . 228

A.4 TheLoggerclass . . . 228

A.5 TheBufferMail concern . . . 228

A.6 TheMailBuffer class . . . 229

(17)

A.7 The SecureConnectionconcern . . . 229 A.8 The Encryptionclass . . . 230

(18)

List of Algorithms

8.1 InitializeSignatures() . . . 141

8.2 StartSignatures() . . . 150

8.3 StartSignature(Concern c) . . . 150

8.4 StartSignatureDistinguishable(Concern c) . . . 150

8.5 StartSignatureClass1(Selector p, ExecutionState state) . . . 151

8.6 StartSignatureClass2(Selector p, ExecutionState state, Set typeSet) . . . . 151

8.7 StartSignatureUndistinguishable(Concern c) . . . 152

8.8 StartSignatureClass3(ExecutionState state) . . . 153

8.9 StartSignatureClass4(ExecutionState state, Set signatureSet) . . . 153

8.10 StartSignatureClass6(ExecutionState state, Set signatureSet) . . . 153

8.11 StartSignatureClass7(ExecutionState state, Set signatureSet, Set typeSet) . 153 8.12 FinalSignatures() . . . 154

8.13 FinalSignature(Concern c) . . . 154

8.14 checkDispatchable(Method m, Concern c) . . . 155

8.15 Checking() . . . 156

8.16 CyclicDependencyConflictCheck() . . . 156

8.17 TypeChecking() . . . 157

8.18 CyclicDispatchConflictCheck() . . . 158

8.19 CyclicDispatchConflictCheckInit() . . . 158

8.20 CyclicDispatchConflictCheckProcess() . . . 159

8.21 CyclicDispatchConflictCheckFinal() . . . 160

9.1 Constructing the intersection of two N F A’s . . . 181

(19)

Part I

Introduction

(20)

Chapter 1

Introduction to AOSD

“The superior man cannot be known in little matters, but he may be entrusted with great concerns.

The small man may not be entrusted with great concerns, but he may be known in little matters.”

Confucius Chinese philosopher & reformer (551 BC - 479 BC) The first two chapters have originally been written by seven M. Sc. students [4, 5, 11, 17, 19, 47, 54] at the University of Twente. The chapters have been rewritten for use in the following theses [6, 7, 8, 20, 21, 46, 52, 53]. They serve as a general introduction into Aspect-Oriented Software Development and Compose?in particular.

1.1 Introduction

The goal of software engineering is to solve a problem by implementing a software system.

The things of interest are called concerns. They exist at every level of the engineering process. A recurrent theme in engineering is that of modularization: separation and lo- calization of concerns. The goal of modularization is to create maintainable and reusable software. A programming language is used to implement concerns.

Fifteen years ago the dominant programming language paradigm was procedural programming. This paradigm is characterized by the use of statements that update state variables. Examples are Algol-like languages such as Pascal, C, and Fortran.

Other programming paradigms are the functional, logic, object-oriented, and aspect- oriented paradigms. Figure 1.1 summarizes the dates and ancestry of several important languages [56]. Every paradigm uses a different modularization mechanism for separating concerns into modules.

Functional languages try to solve problems without resorting to variables. These languages are entirely based on functions over lists and trees. Lisp and Miranda are examples of functional languages.

A logic language is based on a subset of mathematical logic. The computer is pro- grammed to infer relationships between values, rather than to compute output values from input values. Prolog is currently the most used logic language [56].

(21)

1.1 Introduction

object-oriented languages

procedural and concurrent languages

functional languages

logic languages aspect-oriented

languages 2000

1990 1980 1970 1960 1950

Smalltalk Simula

Ada Pascal

Algol-60

Algol-68

C Cobol Fortran

Lisp

ML

Miranda

Prolog

Sina

Sina/st Java

C++

BASIC

VB

C#

AspectJ

2005 Compose*

Hyper/J Legenda:

Influenced by

Figure 1.1: Dates and ancestry of several important languages

A shortcoming of procedural programming is that global variables can potentially be accessed and updated by any part of the program. This can result in unmanage- able programs because no module that accesses a global variable can be understood independently from other modules that also access that global variable.

The Object-Oriented Programming (OOP) paradigm improves modularity by encap- sulating data with methods inside objects. The data may only be accessed indirectly, by calling the associated methods. Although the concept appeared in the seventies, it took twenty years to become popular [56]. The most well known object-oriented languages are C++, Java, C#, and Smalltalk.

The hard part about object-oriented design is decomposing a system into objects.

The task is difficult because many factors come into play: encapsulation, granularity, dependency, adaptability, reusability, and others. They all influence the decomposition, often in conflicting ways [14].

Existing modularization mechanisms typically support only a small set of decompo- sitions and usually only a single dominant modularization at a time. This is known as the tyranny of the dominant decomposition [51]. A specific decomposition limits the ability to implement other concerns in a modular way. For example, OOP modularizes concerns in classes and only fixed relations are possible. Implementing a concern in a class might prevent another concern from being implemented as a class.

Aspect-Oriented Programming (AOP) is a paradigm that solves this problem.

AOP is commonly used in combination with OOP but can be applied to other paradigms as well. The following sections introduce an example to demonstrate the problems that may arise with OOP and show how AOP can solve this. Finally, we look at three particular AOP methodologies in more detail.

(22)

1 p u b l i c c l a s s Add e x t e n d s C a l c u l a t i o n { 2

3 p r i v a t e int r e s u l t ;

4 p r i v a t e C a l c D i s p l a y c a l c D i s p l a y ; 5 p r i v a t e T r a c e r t r a c e ;

6

7 Add () {

8 r e s u l t = 0;

9 c a l c D i s p l a y = new C a l c D i s p l a y () ; 10 t r a c e = new T r a c e r () ;

11 }

12

13 p u b l i c v o i d e x e c u t e (int a , int b ) { 14 t r a c e . w r i t e ( " v o i d Add . e x e c u t e ( int ,

int ) " ) ;

15 r e s u l t = a + b ;

16 c a l c D i s p l a y . u p d a t e ( r e s u l t ) ;

17 }

18

19 p u b l i c int g e t L a s t R e s u l t () {

20 t r a c e . w r i t e ( " int Add . g e t L a s t R e s u l t ()

" ) ;

21 r e t u r n r e s u l t ;

22 }

23 }

(a) Addition

1 p u b l i c c l a s s C a l c D i s p l a y { 2 p r i v a t e T r a c e r t r a c e ; 3

4 p u b l i c C a l c D i s p l a y () { 5 t r a c e = new T r a c e r () ;

6 }

7

8 p u b l i c v o i d u p d a t e (int v a l u e ) {

9 t r a c e . w r i t e ( " v o i d C a l c D i s p l a y . u p d a t e ( int ) " ) ;

10 S y s t e m . out . p r i n t l n ( " P r i n t i n g new v a l u e of c a l c u l a t i o n : " + v a l u e ) ;

11 }

12 }

(b) CalcDisplay

Listing 1.1: Modeling addition, display, and logging without using aspects

1.2 Traditional Approach

Consider an application containing an object Add and an object CalcDisplay. Add in- herits from the abstract class Calculation and implements its method execute(a, b). It performs the addition of two integers. CalcDisplay receives an update from Addif a calculation is finished and prints the result to screen. Suppose all method calls need to be traced. The objects use a Tracerobject to write messages about the program execu- tion to screen. This is implemented by a method called write. Three concerns can be recognized: addition, display, and tracing. The implementation might look something like Listing 1.1.

From our example, we recognize two forms of crosscutting: code tangling and code scattering.

The addition and display concerns are implemented in classesAdd and CalcDisplay respectively. Tracing is implemented in the class Tracer, but also contains code in the other two classes (lines 5, 10, 14, and 20 in (a) and 2, 5, and 9 in (b)). If a concern is implemented across several classes it is said to be scattered. In the example of Listing 1.1 the tracing concern is scattered.

Usually a scattered concern involves code replication. That is, the same code is implemented a number of times. In our example the classesAddandCalcDisplaycontain similar tracing code.

(23)

1.3 AOP Approach In class Addthe code for the addition and tracing concerns are intermixed. In class CalcDisplaythe code for the display and tracing concerns are intermixed. If more then one concern is implemented in a single class they are said to be tangled. In our example the addition and tracing concerns are tangled. Also display and tracing concerns are tangled. Crosscutting code has the following consequences:

Code is difficult to change

Changing a scattered concern requires us to modify the code in several places.

Making modifications to a tangled concern class requires checking for side-effects with all existing crosscutting concerns;

Code is harder to reuse

To reuse an object in another system, it is necessary to either remove the tracing code or reuse the (same) tracer object in the new system;

Code is harder to understand

Tangled code makes it difficult to see which code belongs to which concern.

1.3 AOP Approach

To solve the problems with crosscutting, several techniques are being investigated that attempt to increase the expressiveness of the OO paradigm. Aspect-Oriented Program- ming (AOP) introduces a modular structure, the aspect, to capture the location and behavior of crosscutting concerns. Examples of Aspect-Oriented languages are Sina, AspectJ, Hyper/J, and Compose?. A special syntax is used to specify aspects and the way in which they are combined with regular objects. The fundamental goals of AOP are twofold [16]: first, to provide a mechanism to express concerns that crosscut other components. Second, to use this description to allow for the separation of concerns.

Join points are well-defined places in the structure or execution flow of a program where additional behavior can be attached. The most common join points are method calls. Pointcuts describe a set of join points. This allows us to execute behavior at many places in a program by one expression. Advice is the behavior executed at a join point.

In the example of Listing 1.2 the class Add does not contain any tracing code and only implements the addition concern. Class CalcDisplay also does not contain tracing code. In our example, the tracing aspect contains all the tracing code. The pointcut tracedCallsspecifies at which locations tracing code is executed.

The crosscutting concern is explicitly captured in aspects instead of being embedded within the code of other objects. This has several advantages over the previous code.

Aspect code can be changed

Changing aspect code does not influence other concerns;

Aspect code can be reused

The coupling of aspects is done by defining pointcuts. In theory, this low coupling allows for reuse. In practice reuse is still difficult;

Aspect code is easier to understand

A concern can be understood independent of other concerns;

Aspect pluggability

Enabling or disabling concerns becomes possible.

(24)

1 p u b l i c c l a s s Add e x t e n d s C a l c u l a t i o n { 2 p r i v a t e int r e s u l t ;

3 p r i v a t e C a l c D i s p l a y c a l c D i s p l a y ; 4

5 Add () {

6 r e s u l t = 0;

7 c a l c D i s p l a y = new C a l c D i s p l a y () ;

8 }

9

10 p u b l i c v o i d e x e c u t e (int a , int b ) {

11 r e s u l t = a + b ;

12 c a l c D i s p l a y . u p d a t e ( r e s u l t ) ;

13 }

14

15 p u b l i c int g e t L a s t R e s u l t () { 16 r e t u r n r e s u l t ;

17 }

18 }

(a) Addition concern

1 a s p e c t T r a c i n g {

2 T r a c e r t r a c e = new T r a c e r () ; 3

4 p o i n t c u t t r a c e d C a l l s () :

5 c a l l(* ( C a l c u l a t i o n +) . * ( . . ) ) ||

6 c a l l(* C a l c D i s p l a y . * ( . . ) ) ; 7

8 b e f o r e() : t r a c e d C a l l s () {

9 t r a c e . w r i t e (t h i s J o i n P o i n t. g e t S i g n a t u r e () . t o S t r i n g () ) ;

10 }

11 }

(b) Tracing concern

Listing 1.2: Modeling addition, display, and logging with aspects

1.3.1 AOP Composition

AOP composition can be either symmetric or asymmetric. In the symmetric approach every component can be composed with any other component. This approach is followed by e.g. Hyper/J.

In the asymmetric approach, the base program and aspects are distinguished. The base program is composed with the aspects. This approach is followed by e.g. AspectJ (covered in more detail in the next section).

1.3.2 Aspect Weaving

The integration of components and aspects is called aspect weaving. There are three approaches to aspect weaving. The first and second approach rely on adding behavior to the program, either by weaving the aspect in the source code, or by weaving directly in the target language. The target language can be intermediate language (IL) or machine code. Examples of IL are Java byte code and Common Intermediate Language (CIL).

The remainder of this chapter considers only intermediate language targets. The third approach relies on adapting the virtual machine. Each method is explained briefly in the following sections.

1.3.2.1 Source Code Weaving

The source code weaver combines the original source with aspect code. It interprets the defined aspects and combines them with the original source, generating input for the native compiler. For the native compiler there is no difference between source code with and without aspects. Hereafter, the compiler generates an intermediate or machine

(25)

1.3 AOP Approach language output (depending on the compiler-type).

The advantages of using source code weaving are:

High-level source modification

Since all modifications are done at source code level, there is no need to know the target (output) language of the native compiler;

Aspect and original source optimization

First, the aspects are woven into the source code. Then, the source code is compiled by the native compiler. The produced target language has all the benefits of the native compiler optimization passes. However, optimizations specific to exploiting aspect knowledge are not possible;

Native compiler portability

The native compiler can be replaced by any other compiler as long as it has the same input language. Replacing the compiler with a newer version or another target language can be done with little or no modification to the aspect weaver.

However, the drawbacks of source code weaving are:

Language dependency

Source code weaving is written explicitly for the syntax of the input language;

Limited expressiveness

Aspects are limited to the expressive power of the source language. For example, when using source code weaving, it is not possible to add multiple inheritance to a single inheritance language.

1.3.2.2 Intermediate Language Weaving

Weaving aspects through an intermediate language gives more control over the exe- cutable program and solves some issues, as identified in Section 1.3.2.1 on source code weaving. Weaving at this level allows for creating combinations of intermediate language constructs that cannot be expressed at the source code level. Although IL can be hard to understand, IL weaving has several advantages over source code weaving:

Programming language independence

All compilers generating the target IL output can be used;

More expressiveness

It is possible to create IL constructs that are not possible in the original program- ming language;

Source code independence

Can add aspects to programs and libraries without using the source code (which may not be available);

Adding aspects at load- or runtime

A special class loader or runtime environment can decide and do dynamic weaving.

The aspect weaver adds a runtime environment into the program. How and when aspects can be added to the program depend on the implementation of the runtime environment.

However, IL weaving also has drawbacks that do not exist for source code weaving:

(26)

Hard to understand

Specific knowledge about the IL is needed;

More error-prone

Compiler optimization may cause unexpected results. Compiler can remove code that breaks the attached aspect (e .g., inlining of methods).

1.3.2.3 Adapting the Virtual Machine

Adapting the virtual machine (VM) removes the need to weave aspects. This technique has the same advantages of intermediate language weaving and can also overcome some of the disadvantages of intermediate language weaving, mentioned in Section 1.3.2.2.

Aspects can be added without recompilation, redeployment, and restart of the applica- tion [40, 41].

Modifying the virtual machine also has its disadvantages:

Dependency on adapted virtual machines

Using an adapted virtual machine requires that every system should be upgraded to that version;

Virtual machine optimization

People have spend a lot of time optimizing virtual machines. By modifying the virtual machine these optimizations should be revisited. Reintegrating changes in- troduced by newer versions of the original virtual machine, might have substantial impact.

1.4 AOP Solutions

As the concept of AOP has been embraced as a useful extension to classic programming, different AOP solutions have been developed. Each solution has one or more implemen- tations to demonstrate how the solution is to be used. As described by [12] these differ primarily in:

How aspects are specified

Each technique uses its own aspect language to describe the concerns;

Composition mechanism

Each technique provides its own composition mechanisms;

Implementation mechanism

Whether components are determined statically at compile time or dynamically at run time, the support for verification of compositions, and the type of weaving.

Use of decoupling

Should the writer of the main code be aware that aspects are applied to his code;

Supported software processes

The overall process, techniques for reusability, analyzing aspect performance of aspects, is it possible to monitor performance, and is it possible to debug the aspects.

This section will give a short introduction to AspectJ [24] and Hyperspaces [37], which together with Composition Filters [3] are three main AOP approaches.

(27)

1.4 AOP Solutions

1 a s p e c t D y n a m i c C r o s s c u t t i n g E x a m p l e {

2 Log log = new Log () ;

3

4 p o i n t c u t t r a c e M e t h o d s () :

5 e x e c u t i o n( edu . u t w e n t e . t r e s e . * . * ( . . ) ) ; 6

7 b e f o r e() : t r a c e M e t h o d s {

8 log . w r i t e ( " E n t e r i n g " + t h i s J o i n t P o i n t . g e t S i g n a t u r e () ) ;

9 }

10

11 a f t e r() : t r a c e M e t h o d s {

12 log . w r i t e ( " E x i t i n g " + t h i s J o i n t P o i n t . g e t S i g n a t u r e () ) ;

13 }

14 }

Listing 1.3: Example of dynamic crosscutting in AspectJ

1.4.1 AspectJ Approach

AspectJ [24] is an aspect-oriented extension to the Java programming language. It is probably the most popular approach to AOP at the moment, and it is finding its way into the industrial software development. AspectJ has been developed by Gregor Kiczales at Xerox’s PARC (Palo Alto Research Center). To encourage the growth of the AspectJ technology and community, PARC transferred AspectJ to an open Eclipse project. The popularity of AspectJ comes partly from the various extensions based on it, build by several research groups. There are various projects that are porting AspectJ to other languages, resulting in tools such as AspectR and AspectC.

One of the main goals in the design of AspectJ is to make it a compatible extension to Java. AspectJ tries to be compatible in four ways:

Upward compatibility

All legal Java programs must be legal AspectJ programs;

Platform compatibility

All legal AspectJ programs must run on standard Java virtual machines;

Tool compatibility

It must be possible to extend existing tools to support AspectJ in a natural way;

this includes IDEs, documentation tools and design tools;

Programmer compatibility

Programming with AspectJ must feel like a natural extension of programming with Java.

AspectJ extends Java with support for two kinds of crosscutting functionality. The first allows defining additional behavior to run at certain well-defined points in the ex- ecution of the program and is called the dynamic crosscutting mechanism. The other is called the static crosscutting mechanism and allows modifying the static structure of classes (methods and relationships between classes). The units of crosscutting imple- mentation are called aspects. An example of an aspect specified in AspectJ is shown in Listing 1.3.

The points in the execution of a program where the crosscutting behavior is inserted

(28)

1 a s p e c t S t a t i c C r o s s c u t t i n g E x a m p l e {

2 p r i v a t e int Log . t r a c e ( S t r i n g t r a c e M s g ) { 3 Log . w r i t e ( " - - - M A R K - - - " + t r a c e M s g ) ;

4 }

5 }

Listing 1.4: Example of static crosscutting in AspectJ

are called join points. A pointcut has a set of join points. In Listing 1.3 istraceMethods an example of a pointcut definition. The pointcut includes all executions of any method that is in a class contained by package edu.utwente.trese.

The code that should execute at a given join point is declared in an advice. Advice is a method-like code body associated with a certain pointcut. AspectJ supports before, after and around advice, which specifies where the additional code is to be inserted. In the example both before and after advice are declared to run at the join points specified by the traceMethods pointcut.

Aspects can contain anything permitted in class declarations including definitions of pointcuts, advice and static crosscutting. For example, static crosscutting allows a programmer to add fields and methods to certain classes as shown in Listing 1.4.

The shown construct is called inter-type member declaration and adds a method traceto classLog. Other forms of inter-type declarations allow developers to declare the parents of classes (super classes and realized interfaces), declare where exceptions need to be thrown, and allow a developer to define the precedence among aspects.

With its variety of possibilities, AspectJ can be considered a useful approach for realizing software requirements.

1.4.2 Hyperspaces Approach

The Hyperspaces approach is developed by H. Ossher and P. Tarr at the IBM T.J. Watson Research Center. The Hyperspaces approach adopts the principle of multi-dimensional separation of concerns [37], which involves:

• Multiple, arbitrary dimensions of concerns;

• Simultaneous separation along these dimensions;

• Ability to dynamically handle new concerns and new dimensions of concern as they arise throughout the software life cycle;

• Overlapping and interacting concerns. It is appealing to think of many concerns as independent or orthogonal, but they rarely are in practice.

We explain the Hyperspaces approach by an example written in the Hyper/J lan- guage. Hyper/J is an implementation of the Hyperspaces approach for Java. It provides the ability to identify concerns, specify modules in terms of those concerns, and syn- thesize systems and components by integrating those modules. Hyper/J uses byte code weaving on binary Java class files and generates new class files to be used for execution.

Although the Hyper/J project seems abandoned and there has not been any update in the code or documentation for a while, we still mention it because the Hyperspaces approach offers a unique AOP solution.

Referenties

GERELATEERDE DOCUMENTEN

Keywords: Dynamic compressor selector (DCS), demand-side management (DSM), supply-side management (SSM), platinum mine, compressed air network simulation, real-time energy

These challenges will be divided into present compressor control limitations, shaft compressed air challenges and challenges with the supply lines of the

Docking studies: To complete this study and rationalise the results of the MAO inhibition studies, molecular modelling was carried out and the eighteen compounds

Om te onderzoeken of de druppelwater -pH een invloed heeft op het ontstaan en de ontwikkeling van suikerrot werden 2 kasproeven uitgevoerd. Planten werden verzorgd met druppelwater

under a threshold coverage; change the neighbor-gathering method type, shape parameters and number of compute threads used by PhyML or RAxML; allow the possibility of imputing a

These strands of game studies are mainly interested in the interaction between video games and their players, often dismissing game designers, the construction process and

When op- tical switch 1 forwards the channels from output port 1 of the MZI filter, either λ 1 or λ 2 can be selected by the optical switch 2 according to the binary control.. The