Using Graph Rewriting to Specify Software Architectural Transformations

Similar documents
Wins and Losses of Algebraic Transformations of Software Architectures

Intermediate Code Generation

Compiled Visual Programs by VisPro

Using Architectural Models at Runtime: Research Challenges

Programming Languages Third Edition

Binary Decision Diagrams

Types and Static Type Checking (Introducing Micro-Haskell)

Laboratory 5: Implementing Loops and Loop Control Strategies

Types and Static Type Checking (Introducing Micro-Haskell)

An Architecture for Semantic Enterprise Application Integration Standards

Module 1 Lecture Notes 2. Optimization Problem and Model Formulation

Handout 9: Imperative Programs and State

Semantics via Syntax. f (4) = if define f (x) =2 x + 55.

CREATING CUSTOMIZED DATABASE VIEWS WITH USER-DEFINED NON- CONSISTENCY REQUIREMENTS

Lecturer 2: Spatial Concepts and Data Models

In Our Last Exciting Episode

Eliminating Annotations by Automatic Flow Analysis of Real-Time Programs

Transformation of structured documents with the use of grammar

mapping IFC versions R.W. Amor & C.W. Ge Department of Computer Science, University of Auckland, Auckland, New Zealand

Lecture Notes on Static Semantics

Creating a Lattix Dependency Model The Process

LL(k) Parsing. Predictive Parsers. LL(k) Parser Structure. Sample Parse Table. LL(1) Parsing Algorithm. Push RHS in Reverse Order 10/17/2012

Modal Logic: Implications for Design of a Language for Distributed Computation p.1/53

Basic Structure of Denotational Definitions

Investigation of Metrics for Object-Oriented Design Logical Stability

LOGICAL OPERATOR USAGE IN STRUCTURAL MODELLING

Parsing of UML Package Diagrams 2 UML

5 The Control Structure Diagram (CSD)

Software re-use assessment for quality M. Ramachandran School of Computing and Mathematical Sciences, Jo/m Moores C/mrerszZ?/,

Collaborative Framework for Testing Web Application Vulnerabilities Using STOWS

UNIT-IV BASIC BEHAVIORAL MODELING-I

CS4215 Programming Language Implementation. Martin Henz

Keywords: Abstract Factory, Singleton, Factory Method, Prototype, Builder, Composite, Flyweight, Decorator.

A STUDY OF OBJECT ORIENTED ANALYSIS AND DESIGN

Coping with Conflicts in an Optimistically Replicated File System

INTRODUCING A MULTIVIEW SOFTWARE ARCHITECTURE PROCESS BY EXAMPLE Ahmad K heir 1, Hala Naja 1 and Mourad Oussalah 2

The PCAT Programming Language Reference Manual

Regular Expressions. Agenda for Today. Grammar for a Tiny Language. Programming Language Specifications

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Compiler Design

Ontology Matching with CIDER: Evaluation Report for the OAEI 2008

A model of navigation history

Similarities in Source Codes

Compiler Design. Subject Code: 6CS63/06IS662. Part A UNIT 1. Chapter Introduction. 1.1 Language Processors

1. Introduction to Constructive Solid Geometry (CSG)

Static Analysis Techniques

Statistics Case Study 2000 M. J. Clancy and M. C. Linn

C311 Lab #3 Representation Independence: Representation Independent Interpreters

COMP-421 Compiler Design. Presented by Dr Ioanna Dionysiou

Lecture 2 Arrays, Searching and Sorting (Arrays, multi-dimensional Arrays)

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

CS 6110 S14 Lecture 38 Abstract Interpretation 30 April 2014

EE221 Databases Practicals Manual

Table : IEEE Single Format ± a a 2 a 3 :::a 8 b b 2 b 3 :::b 23 If exponent bitstring a :::a 8 is Then numerical value represented is ( ) 2 = (

Axiomatic Specification. Al-Said, Apcar, Jerejian

A Category-Theoretic Approach to Syntactic Software Merging

Maximal Monochromatic Geodesics in an Antipodal Coloring of Hypercube

CS4215 Programming Language Implementation. Martin Henz

Termination Analysis of the Transformation UML to CSP

Applying March Tests to K-Way Set-Associative Cache Memories

Handling Your Data in SPSS. Columns, and Labels, and Values... Oh My! The Structure of SPSS. You should think about SPSS as having three major parts.

Eclipse Support for Using Eli and Teaching Programming Languages

E-R Model. Hi! Here in this lecture we are going to discuss about the E-R Model.

Artificial Neural Network-Based Prediction of Human Posture

LINEAR PROGRAMMING: A GEOMETRIC APPROACH. Copyright Cengage Learning. All rights reserved.

Introduction to Parsing. Lecture 8

Byzantine Consensus in Directed Graphs

Geometric and Thematic Integration of Spatial Data into Maps

Reducing Directed Max Flow to Undirected Max Flow and Bipartite Matching

A FRAMEWORK FOR EFFICIENT DATA SEARCH THROUGH XML TREE PATTERNS

Formalizing Fact Extraction

UML-Based Conceptual Modeling of Pattern-Bases

DATA MODELS FOR SEMISTRUCTURED DATA

A Tutorial on Agent Based Software Engineering

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Towards Run-time Debugging of Equation-based Object-oriented Languages

Defining a Data Mining Task. CSE3212 Data Mining. What to be mined? Or the Approaches. Task-relevant Data. Estimation.

CS 411 Midterm Feb 2008

Chapter 9: Dealing with Errors

Project and Production Management Prof. Arun Kanda Department of Mechanical Engineering Indian Institute of Technology, Delhi

MIT Top-Down Parsing. Martin Rinard Laboratory for Computer Science Massachusetts Institute of Technology

Detecting Structural Refactoring Conflicts Using Critical Pair Analysis

Basic concepts. Chapter Toplevel loop

Test Cases Generation from UML Activity Diagrams

CSE 12 Abstract Syntax Trees

Flight Systems are Cyber-Physical Systems

Rscript: a Relational Approach to Program and System Understanding

Towards An Integrated Classification of Exceptions

1. NUMBER SYSTEMS USED IN COMPUTING: THE BINARY NUMBER SYSTEM

2.2 Syntax Definition

Towards Automatic Discovery of Deviations in Binary Implementations with Applications to Error Detection and Fingerprint Generation

12 Abstract Data Types

ELEC 875 Design Recovery and Automated Evolution. Architecture Analysis. ELEC 875 Design Recovery and Automated Evolution

Organizing Information. Organizing information is at the heart of information science and is important in many other

LECTURE 8: SETS. Software Engineering Mike Wooldridge

Simulating Task Models Using Concrete User Interface Components

PLD Semester Exam Study Guide Dec. 2018

Chapter 1: Principles of Programming and Software Engineering

ITERATIVE MULTI-LEVEL MODELLING - A METHODOLOGY FOR COMPUTER SYSTEM DESIGN. F. W. Zurcher B. Randell

Representing Product Designs Using a Description Graph Extension to OWL 2

Grade Weights. Language Design and Overview of COOL. CS143 Lecture 2. Programming Language Economics 101. Lecture Outline

Transcription:

Using Graph Rewriting to pecify oftware Architectural ransformations Hoda Fahmy Richard C. Holt Dep t. of Computer cience Dep t. of Computer cience University of oronto University of Waterloo fahmyh@cs.toronto.edu holt@plg.math.uwaterloo.ca Abstract In order to understand, analyze and possibly modify software, we commonly examine and manipulate its architecture. For example, we may want to examine the architecture at different levels of abstraction or repair the architecture if it has deviated from our mental model of the software. We can view such manipulations as architectural transformations, and more specifically, as graph transformations. In this paper, we use graph rewriting to specify these transformations so that we can work towards automating them. pecifically, we use the PROGRE tool to formulate executable graph-rewriting specifications for various architectural transformations in order to demonstrate the strengths of using graph rewriting. We have applied our executable specifications to small graphs and our results confirm the following: Graph rewriting offers a high-level, visual notation that can be used to neatly specify graph modifications as well as support prototype implementation. It also provides a convenient and intuitive framework for exploring various architectural transformations. Keywords: software architecture, graph rewriting, software maintenance, program understanding 1. Introduction In reengineering a software system, one of the first steps is to extract from the code the depencies amongst the low-level software components. Just as important, we need to determine the system hierarchy: how are the modules grouped into subsystems and how are the subsystems grouped into higher level subsystems? It is our position that the component interactions, together with the system hierarchy, define the software s structure or architecture. Upon obtaining the system structure via some extraction tool such as Acacia[5], Rigi[10], or PB[13], we can use a directed typed graph G to represent it (Figure 1). Each node in the graph represents a component in the system, while each edge represents a relation between components. We can have different types of nodes such as module nodes and subsystem nodes; we can have different types of relations such as contain and use. he contain relation defines the system hierarchy, whereas the use relation defines various types of depencies. e c W a b d Figure 1. Graphical representation of a software architecture. Nodes representing subsystems have thick lines; nodes representing modules have thin lines. In this example, contains subsystems and V; contains module e and subsystem W; subsystem W contains modules c and d; and subsystem V contains modules a and b; module a uses b, c and d; c uses b; and d uses e. We often need to manipulate the information provided by the extraction tools in order to understand, analyze and possibly modify the software. In doing so, we are in fact performing transformations on the graph G. he transformations, which are commonly applied to the graph models of the software architectures, can be classified into three classes [6]: V

(1) ransformations for understanding. We use these transformations when we wish to explore and understand the software structure. For example, we may want to create different views of the structure. (2) ransformations for analysis. We use these transformations to discover various kinds of information about the software system. For example, we may want to know what modules interact in a cyclic pattern. his kind of information is commonly used to determine how we will go about modifying the system. (3) ransformations for modification. We use these transformations to change the system structure. For example, we may want to transform the architecture to meet new requirements [4], or we may want to repair the structure if, from our analysis, we find unexpected interactions between subsystems. able 1 lists the transformations which commonly occur during reengineering; they can all be described in terms of graph transformations [6]. ince it would be desirable to automate these transformations, we need to capture these transformations in a mechanical way. Feijs uses a relational approach to model some of these transformations [7], and similarly, Holt uses arski s algebra [8]. In this paper, we use a graph-rewriting formalism to specify these graph transformations since graph rewriting is useful in computations where a graph data structure needs to be modified. Its main advantage over the other approaches is that it offers a high-level, graphical and expressive notation. Each architectural transformation can be specified using a graph-rewrite rule or a set of graph-rewrite rules. he application of a graph-rewrite rule to a host graph G (1) identifies a pattern in G, and then (2) transforms G based on that pattern. We demonstrate the usefulness of graph rewriting using PROGRE, a visual language based on graph rewriting, to formulate executable specifications for these architectural transformations. ection 2 provides an introduction to graph rewriting and PROGRE; ection 3 describes a scenario to which we apply graph rewriting; ection 4 describes the prototype tool developed; ection 5 gives some conclusions. 2. Graph Rewriting & PROGRE Graph rewriting is a promising formalism in which the transformation of graph structures can be modeled and studied [2]. Graph rewriting, or more accurately, graph grammars, were proposed in [12] as an extension to string grammars to manipulate multi-dimensional patterns. Before getting into the details of graph rewriting, we provide an informal description of the way graph rewriting works. able 1. Architectural ransformations Commonly Occurring during Reengineering Class ype Description Architecture Understanding Architecture Analysis Architecture Modification Lifting Hide Interior/ Exterior Diagnostic ifting Forward Repair Reverse Repair Lift low-level use edges up the system hierarchy in order to study the structure at different levels of abstraction [7,8,11] Eliminate information to make the structure more understandable by zooming in and out to concentrate on views of interest [8] Given high-level unexpected edges, lower them down the system hierarchy to identify lowlevel unexpected edges [7,11,15] Mark components that play some role in the desired change of the software structure [6] Alter the extracted architecture (or concrete architecture) to be more consistent with the mental model of the software (i.e, conceptual architecture) [15] Alter the conceptual architecture to be more consistent with the concrete architecture [15] Each graph-rewrite rule minimally consists of LH RH, where LH (Left Hand ide) and RH (right hand side) are graphs. uccessful application of the rule to a graph G performs a local update on G by replacing a subgraph that matches LH by a copy of RH. Refer to Figure 2. If several subgraphs matching LH are found, one subgraph is chosen randomly. Due to the multidimensionality of graphs, there are many ways of attaching the copy of RH to the host graph; thus each graph-rewrite rule needs to specify an embedding. he embedding refers to the way in which a copy of RH is to be attached to the host graph. Figures 2c and 2d show two possible embeddings when rule 2a is applied to graph shown in 2b. If the embedding associated with the rule

LH RH V W e W d a (a) An example of a graph-rewrite rule specifying the deletion of a W-labeled node (b) he host graph. hown shaded is a subgraph matching LH. V V e e d a d a (c) he result of applying the rule shown in (a) to the graph shown in (b) if the embedding specifies that the -labeled node adopts the edges of the W-labeled node as well. (d) he result of applying the rule shown in (a) to the graph shown in (b) if the embedding specifies that the -labeled node does not adopt any new edges Figure 2. Application of a graph-rewrite rule. he graph-rewrite rule shown in (a) is applied to the host graph shown in (b). his transforms the graph in (b) into a result such as (c) or (d), deping on how the copy of RH is embedded in the graph. Note that we use the same notation as the graph shown in Figure 1, and that the graph shown in (b) is in fact a subgraph of that shown in Figure 1. shown in Figure 2a specifies that the node not only retains its edges, but also adopts the node W s edges, the result is the graph shown in Figure 2c. If the embedding specifies that the node gains no new edges, the result is the graph shown in Figure 2d. here are many ways to specify graph-rewrite rules [1]. Here, we choose to use the visual graph-rewriting language PROGRE [2,9,14], since the PROGRE programming environment is the most mature tool currently available for the specification and execution of graph-rewriting systems. Its name is an acronym for

PROgrammed Graph REwriting ystems. One of its main strengths lies in the fact it uses a graphical syntax where appropriate (e.g., for entering LH and RH) but does not exclude textual syntax when it is more natural and concise. Its integrated programming environment offers means for syntax-directed editing, type checking, interactive debugging, graph browsing, and rapid prototyping activities. he remainder of this section will highlight graph rewriting in the context of architectural transformations using PROGRE. In order that the reader understand the basic concepts in graph rewriting, we introduce a minimal set of PROGRE features, and thus, the PROGRE specifications provided in this paper are not very efficient. ection 2.1 describes the PROGRE graph schema; ection 2.2 describes PROGRE rules and ection 2.3 discusses how we can control the order of application of the rules in PROGRE. 2.1. PROGRE Graph chema PROGRE supports the manipulation of directed, attributed, typed graphs, where: Each node has a type. hroughout this paper, we assume we have two types of nodes: modules and subsystems. Each node type belongs to a node class, and node classes are arranged in a is_a hierarchy. For example, the module and subsystem node types belong to the COMPONEN class. Each node class may be associated with a set of attributes. Attributes store information that is not conveniently expressed within the graph structure itself. Attributes may be of any type, including integer, real, and string. hus, each node has a type as well as a (possibly empty) set of attributes. For example, in this paper, nodes belonging to the node class COMPONEN are associated with a name attribute storing the name of the subsystem or module, as well as two boolean attributes, InWrong and InteractsWithOne, which are by default set to false. (InWrong (i.e., in wrong subsystem) is true if there is reason to believe the software component is in the wrong subsystem. InteractsWithOne (i.e., interacts with one subsystem) is true for component x if all the components which use x and is used by x all belong to the same subsystem. We will see in ection 3.2 how these node attributes are used in the repair of a software structure.) Each edge has a type. Parallel edges between nodes are allowed, provided that they are of different types or different directions. hroughout this paper, we assume we have three edge types: contain, use and unexpected. and unexpected edges are permitted between module and subsystem nodes. ubsystem nodes are permitted to have module and subsystem nodes as children (i.e, they can have outgoing contain edges to module and subsystem nodes); however module nodes cannot have any nodes as children. 2.2. PROGRE Rules A PROGRE graph-rewrite rule begins with the keyword production followed by the rule name and parameters. (ee Figure 3.) Next come the graphs LH and RH. Within a production, LH nodes are referred to as `1, `2, `3,... and RH nodes are referred to as 1, 2, 3,... he programmer uses LH and RH to test and modify the graph structure. Attributes are tested by the condition clause and modified by the transfer clause. For example, consider the rule HideInterior (Figure 3). he condition clause states that the Name attribute for node `1 should equal Name, which is passed as a parameter. his rule does not have a transfer clause; refer to Figure 5 for a rule that does. he production rule can be applied to a subgraph only if that the subgraph is isomorphic to LH and also satisfies the condition clause. As was illustrated in Figure 2, a production needs to specify the embedding that should be used for RH. In PROGRE, by default, embeddings use node preserving notation such as 1 =`1 in RH of production HideInterior. his notation means that LH node `1 and RH node 1 refer to the same node in the host graph. his host graph node is not deleted, and it is not recreated when a copy of RH is made. Instead, this node is preserved during the graph transformation. here is no change to the node type, attribute values, or embedding edges. If the user wishes to define a more general embedding, he or she can use the embedding clause of a production. In production HideInterior, the embedding clause specifies that all the incoming and outgoing contain, use, and unexpected edges of node `2 are to be redirected to node 1. It is sometimes necessary to test for the existence of paths between two nodes of LH, where a path is a sequence of edges. PROGRE allows one to do this by defining path conditions. he path condition can be built using sequences, alternatives, and iterations of traversal operations. For instance, we can define an Ancestor path between two component nodes to consist of a sequence of one or more incoming contain edges. If we want to test if node a is an ancestor of node b, we can do this graphically by using an Ancestor-labeled double arrow from node b to node a. (ee example in Figure 4.)

production HideInterior(Name: string) = condition `1: ubsystem `2: COMPONEN `1.Name = Name; embedding redirect --> from `2 to 1 ; redirect <-- from `2 to 1'; redirect --> from `2 to 1'; redirect <-- from `2 to 1'; redirect -Unexpected-> from `2 to 1'; redirect <-Unexpected- from `2 to 1'; Figure 3. he HideInterior rule using PROGRE notation. his rule is used to implement the Hide Interior transformation (able 1). We use this transformation when we are not interested in details of a particular subsystem. he goal is to hide the interior of the subsystem while showing how it interacts with the rest of the system. his rule takes as a parameter the name of the subsystem whose interior we would like to hide. he LH of the rule contains two nodes: node `1 must be a subsystem node, while node `2 must belong to the COMPONEN node class (i.e., it may be a module or subsystem node). he RH contains just one node. he 1 =`1 notation means that node `1 of LH and node 1 of RH refer to the same node in the host graph. he embedding clause specifies that any contain/use/unexpected incoming/outgoing edges from node `2 are to be redirected to node 1. hus, if we apply this rule passing as a parameter ( ) to the graph shown in Figure 2(b), the result is the graph shown in Figure 2(c), if node `2 matches the W-labeled node. (Note that node `2 of LH may also match node e of Figure 2(b)). 1 =`1 ometimes we need to test for the non-existence of nodes, edges, and paths. For example, consider the rule ModuleInWrong shown in Figure 5. his rule determines if a module is not used by and does not use any other component within the same subsystem. We test this in PROGRE by using crossed out nodes. he nonexistence of edges and paths can be tested using the condition clause of the production or tested graphically in the LH by using crossed out edges or paths. Refer to Figure 4. In summary, for a rule to be successfully applied, we need to find a subgraph in G which matches LH (testing for the existence and non-existence of nodes as well as the existence and non-existence of edges and paths). Once a match is found, the condition clause is evaluated. If it is evaluated to true, then we can replace the matched subgraph by a copy of RH, embedding it in the host graph using the embedding specified in the rule. We can then use the transfer clause, if one exists, to modify or set the attribute values of the replacement nodes. 2.3. Organizing the Rules ometimes, we need to control the order of application of the rules. In PROGRE, this is done using transactions. A transaction, beginning with the keyword transaction, is very much like a procedure in other languages. ransactions can have input parameters, output parameters, and call other transactions (including itself). ransaction Lifting given below specifies that we apply production Lift_ (Figure 4) repeatedly until it fails (i.e., no successful match is found) upon which the loop terminates: transaction Lifting = loop begin Lift_ ince we do not pass any parameters, this transaction is applied to the whole graph. Applying Lifting to the graph shown in Figure 1 results in the graph shown in Figure 6. his completes our introduction of graph rewriting and PROGRE. We now turn to an example showing how we can apply graph rewriting to a typical softwaremaintenance problem.

production Lift_ `1:ubsystem `3:ubsystem 1 =`1 3 =`3 `2:Module Ancestor `4:Module Ancestor 2 =`2 4 =`4 condition not (`1 in `3.Ancestor) or not (`3 in `1.Ancestor); Figure 4. he Lift_ graph-rewrite rule using PROGRE notation. his rule is used to implement a lifting transformation (able 1). We use this transformation to raise low-level use relations to higher levels in the system hierarchy in order to study the architecture at different levels of abstraction. pecifically, this rule specifies that if module x uses module y, and x is a descant of PX and y is a descant of PY, then we lift the use edge (x,y) to (PX,PY) only if PX and PY are distinct nodes and PX is not a descant or ancestor of PY. he Ancestor-labeled double arrow is used to test for the existence of an Ancestor path between nodes `2 and `1 as well as nodes `4 and `3. he crossed-out use-labeled edge between nodes `1 and `3 is used to ensure that we only form a new use edge if one does not already exist. he condition clause tests that node `1 is not an ancestor/descant of node `3. We could have tested this condition graphically by using crossed-out Ancestor-labeled double arrows. production ModuleInWrong = `1:ubsystem 1 =`1 `3:Module `4:Module `2:Module 2 =`2 condition `2.InWrong = false; transfer 2'.InWrong := true; Figure 5. he ModuleInWrong graph-rewrite rule using PROGRE notation. his rule is used to implement a sifting transformation (able 1). his rule determines those modules which do not use and are not used by any other module within its subsystem. his suggests that the module has been misplaced and should be moved to another subsystem. Each node in the graph has a boolean attribute InWrong which by default is false. he crossed-out nodes are used to test the non-existence of a sibling of node `2 which uses/is used by node `2, while the condition clause tests that the InWrong attribute is still false. uccessful application of this rule sets InWrong to true via the transfer clause. We will see in ection 3 how this sifting transformation is used during the repair of an architecture.

e c W a b d Figure 6. Applying the Lifting ransaction to the graph shown in Figure 1. Edges resulting from lifting the low-level use relations are shown as thick dashed edges. For example, since c uses b, subsystem W uses subsystem V. 3. Application of Graph Rewriting to Architecture Repair In order to demonstrate the use of architectural transformations in software maintenance, and specifically to demonstrate the potential role of graph rewriting in automating these transformations, we describe a typical scenario in reengineering. In this scenario, we have extracted the structure from a software system and represented it as a graph G. he goal is to repair the structure if it has deviated from our mental model of the system 1. We assume that the extraction process has provided us with only module-module depencies. Our mental (or conceptual model) contains depencies amongst subsystems, rather than modules. Hence, we need to lift the module-module depencies to the subsystem level for comparison with the conceptual model. If there are discrepancies, then we need to determine their causes (i.e., at the module level). We can then try to minimize the discrepancies by restructuring the architecture. In summary, we need to complete the following subtasks: (1) Lifting: We need to lift the low-level uses to the high level in order to determine the subsystem-subsystem depencies. 1 We are currently concentrating on automating repair at the architectural level, not at the source-code level. hus, any modification to the source code reflecting the change at the architectural level needs to be performed manually. V (2) Diagnosis: At this point, we want to identify any unexpected depencies at the subsystem level, and determine the low-level module-module depencies that are causing the unexpected depencies. (3) Repair: Finally, we want to try to minimize the unexpected depencies. here are a variety of lifting functions we can apply to the input graph [7,8,11]. In the last section, we described one such function which is implemented by the Lifting transaction; it repeatedly applies the Lift_ graphrewrite rule (Figure 4) to the input graph until it is no longer applicable. Applying this Lifting transaction to the graph shown in Figure 1 results in the graph shown in Figure 6. Having shown how we can automate lifting, this rest of this section will describe how we can automate diagnosis (ection 3.1) and repair (ection 3.2) using executable graph-rewriting specifications. 3.1. Diagnosis Given only the module-module interactions, it is difficult to determine whether the concrete model of the software is consistent with our conceptual model of the software. However, if we perform lifting to determine how the subsystems interact (Figure 6), it becomes easier to determine the inconsistencies. After examining the graph shown in Figure 6, let us assume that we have determined that subsystem unexpectedly deps on V; we expected that uses V but not vice versa. We can use the parameterized graph-rewrite rule Make_Unexpected to change the label of the edge from to V from use to unexpected. his rule is illustrated in Figure 7. We now want to identify lower-level edges which are causing the high-level unexpected edge. We do this by applying the Lower_Unexpected transaction (not shown here) which does the opposite of the lifting transformation. pecifically, if there is an unexpected edge (x,y), then any use edge from x or any of x s descant, to y, or any of y s descants, is changed to an unexpected edge. We define a transaction named Diagnosis to describe this two step process: transaction Diagnosis( Name, Name : string) = Make_Unexpected ( Name, Name ) & Lower_Unexpected Applying transaction Diagnosis(, V ) to the graph shown in Figure 6 results in the graph shown in Figure 8. We can apply this transaction for each high-level unexpected depency identified by the user.

production Make_Unexpected (Name, Name: string) = condition (`1.Name = Name) and (`2.Name= Name); Figure 7. he Make_Unexpected graph-rewrite rule. It is used to convert a use-labeled edge to an unexpected-labeled edge. he parameters define the source and target node names of the use-labeled edge to be converted. e c W a b d Figure 8. Applying the Diagnosis ransaction to the graph shown in Figure 6. he problematic or unexpected relations are shown as thick dashed edges. Once we assert that should not use V, then this information is lowered down the system hierarchy. We find out that W should not use V and c should not use b. 3.2. Repair `1:COMPONEN `1=Node Unexpected `2:COMPONEN `2=Node In our scenario, we have analyzed the system and determined that there are inconsistencies between it and V our conceptual model. Now we would like to repair the structure to make it more consistent with the conceptual model. One way to do this is to perform kidnapping [15]. Kidnapping moves a module or subsystem from its original subsystem to a new one. It is a safe transformation because it does not modify the source code, and so the code s semantics are not changed. ran [15] performed kidnapping to repair Linux. For example Linux has seven top-level subsystems, two of which are the Network Interface subsystem and the Process cheduler subsystem [3]. he Process cheduler subsystem unexpectedly deped on the Network Interface, and ran determined that the inet.h module, which is only used by modules in the Network Interface subsystem, was the cause of this depency. By having the Network Interface subsystem kidnap inet.h, the unexpected depency was eliminated. his type of action is ideal for automation. We will now illustrate how we can automate the kidnapping of modules from one subsystem to another using graph rewriting. First of all, we need to determine good kidnapping candidates. One possibility is to consider those modules which do not use and are not used by any module within its subsystem. hose modules have perhaps been misplaced. he question becomes, which subsystem should kidnap the misplaced module? If the misplaced module x uses and is used by modules which all belong to the same subsystem Y, then subsystem Y should kidnap module x. We can apply sifting transformations (able 1) to determine these ideal kidnapping candidates; specifically we can define a PROGRE transaction named ifting which applies the rule ModuleInWrong shown in Figure 5 as well as the transaction ModuleInteractsWithOne, not given here. As mentioned in ection 2.1, the COMPONEN node class has two boolean attributes, InWrong and InteractsWithOne, which by default are set to false. Applying the rule ModuleInWrong repeatedly to the graph sets the InWrong attribute to true for all misplaced modules. he transaction ModuleInteractsWithOne sets the InteractsWithOne attribute to true for all modules which interact with only one subsystem. Once we determine which modules are good candidates to be kidnapped into another subsystem, we can apply a kidnapping transformation to actually move the module from one subsystem to another if it is involved in an unexpected depency. his transformation is expressed in the rules KidnapModule1 and KidnapModules2. (Only KidnapModule1 is shown in Figure 9; KidnapModule2 is similar to KidnapModule1 except node `2 is the target of an unexpected-labeled edge rather than the source.) Once the module is kidnapped, its InWrong value is set to false (refer to the transfer clause), and the unexpected-labeled edge becomes a uselabeled edge (RH of the production). After we minimize

the low-level unexpected-labeled edges by applying KidnapModule1 and KidnapModule2 rules, we need to eliminate high-level unexpected-labeled edges which are no longer relevant. o do so we can apply the graphrewrite rule FixUnexpectedEdges not shown here. In summary, assuming, we have applied the transaction ifting, our repair transformation takes the form of the following PROGRE transaction: transaction aferepairbykidnapping = loop begin KidnapModule1 or KidnapModule2 & loop begin FixUnexpectedEdges ince the kidnapped modules are not used by and do not use any modules outside of their new subsystem, we do not run the risk of creating new unexpected depencies by performing this type of repair. However, it could very well be that successful application of the transaction aferepairbykidnapping does not remove any high-level unexpected-labeled edges. Applying aferepairby- Kidnapping to the graph shown in Figure 8 results in the graph shown in Figure 11. In this case, there is only one possible place to apply the kidnapping transformation (KidnapModule1) ubsystem V kidnaps module c from ubsystem W. his results in the removal of unexpected edges (c,b), (W,V) and (,V). here are many types of repair that we may perform to help minimize the unexpected depencies. In this section, we have chosen a simple one in order that the graph-rewriting concepts presented in this paper are made clear. Other types of repair are discussed in [15] and are beyond the scope of this paper. 3.3. ummary In this section, we illustrated how we can use graph rewriting to specify and automate various architectural transformations. We demonstrated the potential use of graph rewriting by describing a problem and showing how we can help solve it using graph rewriting. Here, we summarize the solution by defining the PROGRE transaction MAIN, which calls the various transactions given in this section: transaction MAIN = Lifting & ifting & Diagnosis(Name,Name) & aferepairbykidnapping production KidnapModule1 = condition `2.InWrong = true and `2.InteractsWithOne = true; transfer 2'.InWrong := false; Figure 9. A Graph-rewrite rule to implement kidnapping. his rules moves a module which is involved in an unexpected depency to another subsystem if it does not use or is not used by any module within its subsystem and yet the modules it uses/is used by all belong to the same subsystem. e `1:ubsystem `2:Module `1:ubsystem `2:Module W a c b d Unexpected `3:ubsystem `4:Module Figure 10. Repairing the system shown in Figure 8. We have applied the aferepairbykidnapping transaction to the graph shown in Figure 8. When we kidnap c from subsystem W to subsystem V then W and no longer use V. Note that component c has all its original use edges. V `3:ubsystem `4:Module

his transaction is applied to a graph representing a software architecture where only low-level use relations are provided (such as that shown in Figure 1). 4. Prototype Generation and Results We used the PROGRE tool to automatically generate C code for the specifications we formulated. After compiling the code, we obtained a prototype system, which allowed us to execute the specifications. he prototype allows us to read in and display an input graph and apply the various architectural transformations to it. Each rule and transaction specified appears as a menu item within the prototype environment and the user can choose the rule or transaction which she or he wants applied to the graph. For example, we can choose the rule Lift_ (Figure 4) which results in just one application of the rule if a successful match is found. Or, we can choose the transaction MAIN given above, which results in the application of the Lifting, ifting, Diagnosis 2 and aferepairbykidnapping transactions all in that order. We applied the transformations outlined in this paper to graphs, consisting of less than one hundred nodes, which allowed us to test for the correctness of our specifications. Although we made use of many PROGRE features to increase efficiency, PROGRE is not able to manipulate larger graphs efficiently. his is an obvious obstacle if one is to use this tool to perform software architectural transformations, especially since most software systems consist of hundreds of modules. Much research in the graph rewriting community is currently focussed on the development of efficient graphrewriting tools [2]. Regardless of PROGRE performance, our results confirm that graph rewriting offers a high-level, visual notation that can be used to neatly specify graph modifications as well as support prototype implementation. It also provides a convenient an intuitive framework for describing architectural transformations in a unified way. 5. Conclusions In order to automate the architectural transformations that commonly occur during reengineering, we need to specify them in a formal way. In this paper, we have successfully shown how we can specify them using graph rewriting. By testing our specifications on small graphs using the PROGRE tool, we have demonstrated graph rewriting s main strength. It provides a clear, intuitive, high-level, visual description of architectural transformations. Having obtained such a description, we can now work 2 If the parameters of the Diagnosis transaction are not given explicitly (e.g., "","V"), then the user is prompted for them. towards automating many of the transformations. Perhaps as more research focuses on the development of efficient graph-rewriting tools, we will be able to use these tools to perform transformations on architectures of large software systems. References [1] D. Blostein, H. Fahmy, A. Grbavec. Issues in the Practical of Graph Rewriting, Lecture Notes in Computer cience, Vol. 1073, 1996, pp. 38-55. [2] D. Blostein and A. chürr. Computing with Graphs and Graph ransformations, oftware- Practice and Experience, Vol. 29(3), pp. 197-217, 1999. [3] I.. Bowman, R.C. Holt, and N.V. Brewster. Linux as a Case tudy: Its Extracted oftware Architecture, Proceedings in the 21 st International Conference on oftware Engineering, Los Angeles, May 1999. [4].J. Carriere,. Woods, and R. Kazman. oftware Architectural ransformation, Proc. 1999 Working Conference on Reverse Engineering, Oct. 1999. [5] Y.-F.Chen, M.Y. Nishimoto, and C.V. Ramamoorthy. he C Information Abstraction ystem, IEEE ransactions on oftware Engineering, Vol. 16, pp. 325-334, 1990. [6] H. Fahmy and R.C. Holt. oftware Architecture ransformations, to appear in the Proceedings of the International Conference on oftware Maintenance, an Jose, Oct. 2000. [7] L. Feijs, R. Krikhaar and R. Van Ommering. A Relational Approach to upport oftware Architecture Analysis, oftware-practice and Experience, Vol. 28(4), pp. 371-400, April 1998. [8] R.C. Holt. tructural Manipulations of oftware Architecture Using arski Relational Algebra, Proceedings of the 5th Working Conference on Reverse Engineering 1998, Honolulu, Hawaii, October 12-14, 1998. [9] C.E. Hrischuk. Implementing Angio race Analysis using the Graph Rewriting ool PRORE. Available at http://www.sce.carleton.ca/rads/ceh/graph_gram.html. [10]H. Muller, O. Mehmet,. illey, J. Uhl. A Reverse Engineering Approach to ubsystem Identification, oftware Maintenance and Practice, Vol. 5, pp. 181-204, 1993. [11] G.C. Murphy, D. Notkin, and K. ullivan. oftware Reflexion Models: Bridging the Gap Between ource and High-Level Models, Proceedings of the hird ACM ymposium on the Foundations of oftware Engineering, Oct. 1995. [12] J.Pfaltz and A. Rosenfeld, Web grammars, Proc. 1 st Int. Joint Conf. Artificial Intelligence, Washington, 1969, pp. 599-609. [13]Portable Bookshelf (PB) tools. Available at http://www.turing.cs.toronto.edu/pbs [14] PROGRE. Available at http://www-i3.informatik.rwthaachen.de/research/progres/release.html. [15]J.B. ran and R.C. Holt. Forward and Reverse Repair of oftware Architecture, Proceedings of the IBM CA Conference, Nov. 1999.