A Methodology for the Speci cation of Java Components and Architectures Stelvio Cimato
Technical Report UBLCS-99-14 July 1999
Department of Computer Science University of Bologna Mura Anteo Zamboni 7 40127 Bologna (Italy)
The University of Bologna Department of Computer Science Research Technical Reports are available in gzipped PostScript format via anonymous FTP from the area ftp.cs.unibo.it:/pub/TR/UBLCS or via WWW at URL http://www.cs.unibo.it/. Plain-text abstracts organized by year are available in the directory ABSTRACTS. All local authors can be reached via e-mail at the address last-name @cs.unibo.it. Questions and comments should be addressed to
[email protected].
Recent Titles from the UBLCS Technical Report Series 99-1
Deciding and Axiomatizing ST Bisimulation for a Process Algebra with Recursion and Action Re nement, M. Bravetti, R. Gorrieri, February 1999.
99-2
A Theory of Eciency for Markovian Processes, M. Bernardo, W.R. Cleaveland, February 1999.
99-3
A Reliable Registry for the Jgroup Distributed Object Model, A. Montresor, March 1999.
99-4
Comparing the QoS of Internet Audio Mechanisms via Formal Methods, A. Aldini, M. Bernardo, R. Gorrieri, M. Roccetti, March 1999.
99-5
¨ Babao˘glu, April 1999. Group-Enhanced Remote Method Invocations, A. Montresor, R. Davoli, O.
99-6
Managing Complex Documents Over the WWW: a Case Study for XML, P. Ciancarini, F. Vitali, C. Mascolo, April 1999.
99-7
Data-Flow Hard Real-Time Programs: Scheduling Processors and Communication Channels in a Distributed Environment, R. Davoli, F. Tamburini, April 1999.
99-8
The MPS Computer System Simulator, M. Morsiani, R. Davoli, April 1999.
99-9
Action Re nement, R. Gorrieri, A. Rensink, April 1999.
99-10
Proceedings of the Workshop on Virtual Documents, Hypertext Functionality and the Web, M. Milosavljevic, F. Vitali, C. Watters, May 1999.
99-11
An Algebraic Model for Evaluating the Performance of an ATM Switch with Explicit Rate Marking, A. Aldini, M. Bernardo, R. Gorrieri, June 1999.
99-12
Simulative and Experimental Analysis of an Adaptive Playout Delay Adjustment Mechanism for packetized Voice across the Internet, M. Roccetti, V. Ghini e G. Pau, June 1999.
99-13
Theory and Application of Extended Markovian Process Algebra,
M. Bernardo, July 1999
(Ph.D. Thesis).
99-14
A Methodology for the Speci cation and Veri cation of Java Components and Architectures, S. Cimato, July 1999 (Ph.D. Thesis).
99-15
Parallel Discrete Event Simulation Supported by Coordination Languages Based on the Generative Paradigm, A. Fabbri, July 1999 (Ph.D. Thesis).
99-16
Analysis and Automatic Detection of Information Flows in Systems and Networks, R. Focardi, July 1999 (Ph.D. Thesis).
Dottorato di Ricerca in Informatica Universit a di Bologna, Padova, Venezia
A Methodology for the Speci cation of Java Components and Architectures Stelvio Cimato February 1999
Coordinatore: Prof. Ozalp Babaoglu
Tutore: Prof. Paolo Ciancarini
Abstract The design and the implementation of large software systems is an ever lasting challenge for software developers. Currently, the development of the World Wide Web and Internet, and the diusion of personal computers and local area networks complicates more and more the scenario in which software engineers have to develop their applications. The dominant computing paradigm is lrapidly shifting from monolithic applications running on an isolated computer towards distributed systems running on platforms heterogeneous both for hardware and software. An important idea to manage this increasing complexity is to recognize and describe the overall structure of a software system, in order to identify its fundamental components and to decompose the original problem in smaller subproblems more easily resolvable. Following this approach already experienced design solutions can be successfully reused, simplifying and making more eective the software development process. Design patterns, software architecture, and component based software development are design techniques that enhance the re-usability of software by applying the practical approach of `divide and conquer" to software design and implementation. Formal notations should guide software builders in the development of complex applications, in order to make them able to reason on the properties on the design and to ensure a successful result of their work. In spite of a multi-faced growing community of computer users, Java is making software development scenario more uniform, due to its features of portability,
exibility, and security, which have determined its success. Java comes with a set v
of built-in features that meet the needs of designers involved in the construction of distributed systems. Furthermore, Java extensions like RMI (Remote Method Invocation), Java Beans and JavaSpaces, enrich the basic language framework with advanced facilities which have to be mastered in order to design eective distributed applications. However, all their fundamental features are exposed informally, with a number of examples and tutorials. In this work we address the formal speci cation of Java classes and provide a methodology to support the speci cation of Java components. We provide an interface speci cation language for the speci cation of modules written in Java, and explore the use of such a notation for the de nition of components to be employed to design concrete applications. Furthermore we provide a reduction semantics for the object oriented kernel of Java, extending then the treatment to concurrency and distribution relying on the Chemical Abstract machine framework. The basic mechanisms of Java are investigated and formally de ned, paving the way for the formal evaluation of Java programs. The semantics is then exploited to de ne a veri cation method for Java components, such that their properties can be formally proved.
vi
Acknowledgements At the end of this long period of study I have to thank all the people who have helped me along the way and without whom this work would not have been concluded, people supporting me both with their intellectual and emotional help. First of all, I would like to thank my supervisor, prof. P. Ciancarini who guided me in this experience and whose insightful feedback has helped me to carry on my research work. A particular thank is due to prof. C. Laneve for the discussions about Java semantics and his comments on the earlier drafts of this dissertation. I would like to thank also the referees for their contributions and their suggestions to improve my work. I would like also to thank my colleagues who shared this experience with me, Marco, Rik and Alessandro (the X-Doctorates) and the other people (students and non) who joined the group and made more pleasant to work in our (narrow) oce: Gigio, Alberto, Mario, Davide, Irene, Agata, Cecilia, Marco, Luciano, Fabio and Nadia. Finally I have to thank my family, especially my mother and my grandmother who always support me in the challenges of life.
vii
Contents Abstract
v
Acknowledgements
vii
List of Tables
xii
List of Figures
xiii
1 Introduction
1
1.1 Overview . . . . . . . . . . . . . . . . 1.2 Motivation . . . . . . . . . . . . . . . 1.3 The approach . . . . . . . . . . . . . 1.3.1 A Notation for Components . 1.3.2 An Architectural Language . 1.3.3 A Semantics for Java objects . 1.4 Summary of contributions . . . . . . 1.5 Structure of the thesis . . . . . . . .
2 Background
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
2.1 Introduction . . . . . . . . . . . . . . . . . . . . 2.2 Object Oriented design . . . . . . . . . . . . . . 2.3 Architectural design . . . . . . . . . . . . . . . 2.3.1 Abstract model of Software Architecture 2.3.2 Architectural style . . . . . . . . . . . . 2.4 Design Patterns . . . . . . . . . . . . . . . . . . viii
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
1 2 8 9 10 11 11 12
13 13 14 15 15 17 18
2.5 Component-based software development 2.5.1 CORBA/OpenDoc . . . . . . . . 2.5.2 COM/OLE/ActiveX . . . . . . . 2.6 Java . . . . . . . . . . . . . . . . . . . . 2.6.1 Java characteristics . . . . . . . . 2.7 Discussion . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
3 Specifying Java Components
3.1 A formal framework for Java components and architectures . 3.1.1 Components . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Connectors . . . . . . . . . . . . . . . . . . . . . . . 3.2 Ljala: a formal speci cation language for Java components . 3.2.1 Informal description . . . . . . . . . . . . . . . . . . 3.2.2 Overview of LSL . . . . . . . . . . . . . . . . . . . . 3.2.3 An interface language for Java . . . . . . . . . . . . . 3.2.4 Supporting concurrency . . . . . . . . . . . . . . . . 3.2.5 Formal model of Objects and State . . . . . . . . . . 3.2.6 A concurrent speci cation . . . . . . . . . . . . . . . 3.2.7 Other interface languages . . . . . . . . . . . . . . . 3.3 The abstract model of components and connectors . . . . . . 3.4 An example: client and server components . . . . . . . . . . 3.5 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Specifying Architectures of Java Components 4.1 4.2 4.3 4.4 4.5 4.6
Introduction . . . . . . . . . . . Con gurations . . . . . . . . . . Semantics of con gurations . . . Specifying complex components Description of styles . . . . . . JavaBeans . . . . . . . . . . . . 4.6.1 Modeling beans . . . . .
ix
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
19 20 23 24 25 26
28 28 30 30 31 32 33 37 40 42 46 48 48 52 54
59 59 60 62 64 65 66 67
4.7 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.7.1 Formalisms in software architecture . . . . . . . . . . . . . 73 4.7.2 Architectural Description Languages . . . . . . . . . . . . 74 4.7.3 Larch & Software Architecture . . . . . . . . . . . . . . . . 76
5 A Reduction Semantics for Java
77
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 5.1.1 Our approach . . . . . . . . . . . . . . . . . . . . . . . . . 78 5.2 The object oriented kernel of Java . . . . . . . . . . . . . . . . . . 79 5.2.1 Class declarations . . . . . . . . . . . . . . . . . . . . . . . 81 5.2.2 Semantics of declarations . . . . . . . . . . . . . . . . . . . 83 5.3 Basic notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.4 Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 5.4.1 The abstract model . . . . . . . . . . . . . . . . . . . . . . 89 5.4.2 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 5.4.3 Declaration of local variables . . . . . . . . . . . . . . . . . 93 5.4.4 Commands and Expressions . . . . . . . . . . . . . . . . . 94 5.4.5 Method invocation . . . . . . . . . . . . . . . . . . . . . . 99 5.5 Advanced features . . . . . . . . . . . . . . . . . . . . . . . . . . 104 5.5.1 Access to the type system . . . . . . . . . . . . . . . . . . 105 5.5.2 Dynamic Class Loading . . . . . . . . . . . . . . . . . . . 108 5.6 Saraswat's bug . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 5.6.1 The code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 5.7 Reasoning about programs: a sample set of axioms . . . . . . . . 118 5.8 Related work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 x
6 Modeling concurrency in Java
6.1 Introduction . . . . . . . . . . 6.1.1 The chemistry . . . . . 6.1.2 A cham for Java . . . 6.2 Concurrency in Java . . . . . 6.3 Modeling concurrent threads . 6.4 Discussion . . . . . . . . . . .
. . . . . .
7 Veri cation 7.1 7.2 7.3 7.4 7.5 7.6 7.7
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
Introduction . . . . . . . . . . . . . . . . . . . . The veri cation problem . . . . . . . . . . . . . Axiomatic semantics of programming languages The approach . . . . . . . . . . . . . . . . . . . Example . . . . . . . . . . . . . . . . . . . . . . Concurrent speci cations . . . . . . . . . . . . . Related Work . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
126 126 127 129 129 132 140
142 142 143 145 147 151 157 160
8 Conclusions
163
References
168
8.1 Future Research . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
xi
List of Tables 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11 5.12
Shape of classes . . . . . . . . . . . . . . . . . . Semantics of new . . . . . . . . . . . . . . . . . Semantics of local variable declarations . . . . . Semantics of sequential commands . . . . . . . Semantics of expressions . . . . . . . . . . . . . Semantics of method invocation . . . . . . . . . Rules for methods in class Class . . . . . . . . Rules for getClass in class Object . . . . . . . Revised semantics of new and of var declaration Dynamic class loading . . . . . . . . . . . . . . Semantics of methods in ClassLoader . . . . . Axioms for Java . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
83 93 95 96 98 104 108 108 112 112 113 119
6.1 6.2 6.3 6.4 6.5
Modi ed members declaration . . . . . . Semantics of thread invocation . . . . . . Revised semantics of method invocation Semantics of lock and unlock operations Semantics of thread management . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
133 134 135 137 138
xii
. . . . .
. . . . .
. . . . .
. . . . .
List of Figures 2.1 CORBA framework . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.2 Steps to create running CORBA objects . . . . . . . . . . . . . . 22 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18
Schema of a component . . . . . . . . . . . . . . . . . . LSL and LIL layers in Larch speci cations . . . . . . . Trait for a stack . . . . . . . . . . . . . . . . . . . . . . A speci cation of a bounded counter . . . . . . . . . . Traits de ning the model for basic objects and actions Trait for typed objects . . . . . . . . . . . . . . . . . . Trait de ning State . . . . . . . . . . . . . . . . . . . . Speci cation of a concurrent counter . . . . . . . . . . Traits for generic components and connectors . . . . . Hierarchy of components . . . . . . . . . . . . . . . . . Hierarchy of connectors . . . . . . . . . . . . . . . . . . Trait for a counter component . . . . . . . . . . . . . . Trait for a Client component . . . . . . . . . . . . . . . Trait for a Server component . . . . . . . . . . . . . . . Trait for a socket . . . . . . . . . . . . . . . . . . . . . Speci cation of a Server component class . . . . . . . . Speci cation of a socket component class . . . . . . . . A Java class implementing a socket . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
29 32 35 38 42 44 45 47 49 50 51 51 53 54 55 56 57 58
4.1 Structure of a con guration module . . . . . . . . . . . . . . . . . 61 4.2 Con guration module for a c-s system . . . . . . . . . . . . . . . 61 xiii
4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11
The hierarchic description of components . . . . Trait for a bean . . . . . . . . . . . . . . . . . . . Button trait in the hierarchy of component traits Trait for a button . . . . . . . . . . . . . . . . . . Speci cation of a button . . . . . . . . . . . . . . Beans interaction . . . . . . . . . . . . . . . . . . Trait for adapters . . . . . . . . . . . . . . . . . . Speci cation of a ButtonAdaptor . . . . . . . . . Con guration module for the button system . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
64 68 69 69 70 71 71 72 73
5.1 The initial class environment . . . . . . . . . . . . . . . . . . . . . 90 5.2 The type hierarchy for wrapper classes . . . . . . . . . . . . . . . 106 5.3 Bridge con guration for classes in Saraswat example . . . . . . . . 115 6.1 Thread lifecycle in Java . . . . . . . . . . . . . . . . . . . . . . . 130 7.1 7.2 7.3 7.4 7.5
Trait for a simple Counter . . . . . . . . Speci cation for a Counter . . . . . . . . Implementation of a counter . . . . . . . Speci cation of a concurrent counter . . Implementation of a concurrent counter .
xiv
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
152 153 154 158 159
Chapter 1
Introduction 1.1 Overview The design and the implementation of large software systems is an ever lasting challenge for software developers. The ubiquitous use of computer systems in a large number of elds of human activities, proposes dicult problems to be solved on large scale. Such an increasing complexity of present computer systems compels software builders to research ecient abstractions to simplify and make more eective the software development process. A successful approach is the practical application of the \divide and conquer" paradigm to software design and implementation. The basic idea is to recognize and describe the overall structure of a software system, in order to identify its fundamental components and to reuse already experienced design solutions. Techniques such as design patterns, software architectural design, and component based software development are based on the reuse of successful solutions to formerly solved design problems. [SG96, GHJV95, Szy98, Cle96]. Currently, the development of the World Wide Web and the Internet, and the diusion of personal computers and local area networks complicates more and more the scenario in which software engineers have to develop new applications. From monolithic applications running on isolated computers, the dominant computing paradigm is quickly shifting towards distributed systems running on platforms heterogeneous both for hardware and software used [BW96, MM97].
2
Chapter 1. Introduction
Component-based technologies allow software developers to reduce design costs in terms of time and resources employed to develop new products [Nie95]. For software industries which are facing today both economical and technological challenges, the possibility to reduce costs and to shorten time-to-market is extremely important. Software-houses having shrinking budgets and involved in a wild market competition develop software product families, where already produced software parts become capital assets which can be reused in the cycle of software development. The reduced time to release the newer version of an existing application or to build a new one from scratch is a very important feature which can determine the success of a product in the market (and the success of the software house itself). This approach which promotes reuse is causing a paradigm shift from producing whole, monolithic applications to consuming and assembling already produced software parts [GP95, SG96]. The release of the rst implementation of the Java language [AG96] had a strong impact on the software industry. The enormous diusion of such a language and platform and its features of portability, exibility, and security, is making the software development scenario more uniform. Notably, Java comes with a set of built-in features that meet the needs of designers involved in the construction of systems made of distributed components. Java extensions like RMI (Remote Method Invocation) [Sun96b], Java Beans [Sun96a], Java-IDL, and JavaSpaces enrich the basic general framework with advanced facilities which have to be mastered in order to design distributed applications.
1.2 Motivation We take for granted that formal notations should guide software builders in the development of applications, in order to be more con dent in the result of their work [Jon96, LG86]. When developing Java (component-based) applications, software designers have few speci c tools and techniques at their own disposal to formally reason on the resulting system. Generic speci cation languages, such as
Chapter 1. Introduction
3
Z [Spi92, CCM97] or UML [HW98], can be eciently exploited as well as architectural description languages, such as Wright [All97] or Darwin [MK96], but the generality of the model does not catch all the features of the underlying programming language (Java) and the abstractions needed to make formal descriptions practical and eective. On the other hand, practical approaches for componentbased software development (VisualBasic [ViB92], JavaBeans [Sun96a] , Delphi [Bor95], and others), have a restricted application domain and oer frameworks for the composition of software modules but suer from the lack of a wellunderstood formal foundation. The bene ts expected from the application of a formal methodology are the removal of ambiguities in the design and the capability oered to the designer for the analysis and the veri cation of properties of the design. However, reuse as a goal of component based software development is also hampered by the poor use of formal notations. Informal or under-speci ed software components force designers to look into implementation details to consider their behavior and the side eects they entail on the whole system. A judicious application of formal methods can detect faults earlier in the development process, thereby reducing mistakes during the dierent phases of the design. By reasoning on dierent representations of the overall problem at dierent levels of abstraction, formal methods can focus and validate crucial elements of requirements or of design. In the development of component based software applications written in a speci c programming language, we recognize several levels where formal methods can contribute:
a formal speci cation language can be used to describe the behaviour of each software module or component enhancing its possible reuse. Components need a well founded model such that their properties and the assumptions they make on the external environment are clearly exposed. Since the interface they oer and their behaviour are the crucial points which de ne
4
Chapter 1. Introduction
a component we will adopt a behavioural interface language [Win87], for the speci cation of software components.
formal reasoning on systems resulting from the composition of basic components ensures that the developed application satis es some crucial properties and its behaviour ful lls the requirements; putting components together is not sucient to guarantee the correct behaviour of the resulting system, on the contrary frequent mismatches occur due to implicit or wrong assumptions on the underlying component framework [GAO95].
at the lower level, a formal semantics for the language constructs can be
provided in order to translate programs in their formal equivalent. The resulting translation can be submitted to formal reasoning using the mathematical framework or the automatic tools available for the chosen formalism. A formal semantics for the programming language is necessary to avoid ambiguities and bugs which are present in the language's reference manuals [GJS96, Qia97] or in its implementations [DFW96, Sar97]
Formal Methods and Software Architecture The importance of software
architecture in the software development process is con rmed by the increasing interest focused on this emerging eld of research both in academia and industry. The architectural level of design is concerned with the overall structure of the system which is regarded as the composition of several interacting modules. A textual description including informal de nitions has often accompanied the description of the architecture of a system being developed, allowing the recognition of the composition of its structure. Current research aims to support the practice of architectural design with formal methods and techniques in order to provide the speci er with the capability of making assumptions on the behavior of each single component as well as of the composed systems. Fixing the meaning of the rich informal vocabulary used to describe components and their interrelationships should help to reason on the correctness of the resulting composition. A
Chapter 1. Introduction
5
formal framework serves as the basis to assess functional global properties of the system, as well as non-functional properties related to performance or security, for example. A large amount of work in software architecture is directed to the de nition of formalisms and speci cation techniques. Several architectural description languages have been developed to provide software designers with notations and tools to specify and reason about architectural designs. Some frameworks give the designer an environment to build systems according to a speci c architectural style [GAO94], where a style prescribes the type of components and connectors that can be used and the rules for their interconnections. Other general-purpose architectural languages support the description of the architecture of a system through behavioral speci cation. In [S+95], architectural descriptions can be compiled to obtain executable code. A rapid prototype for the simulation of system behavior can be constructed as in [L+95]. General speci cation notations have also been exploited in the study of software architectures such CSP [GAO94] and CHAM [IW95] to give behavioral speci cation for the system being developed. The growing interest in recent years for this eld of research has led to the organization of speci c conferences [GTP95, Wol97]. Some work has been done on the foundations of software architecture discipline [SG96], on the de nition of architectural description languages [GMW96], on the description of general or speci c styles [AAG95, GAO94], and on developing techniques for the evaluation, validation and implementation of concrete software architectures [S+ 95, L+ 95]. However, formal methods play only a marginal role in current practice. The architecture of a system is often depicted informally through box and lines diagrams, which provide a schema of the overall structure of the system, but which give a little information on the functionalities and the interactions among components. Even commonly accepted descriptions as 'client-server' or 'pipe lter' give an intuition of the composition of a determined system, but are of little usefulness if there is not a precise de nition of their meaning. Furthermore, the lack of a formal framework for the design and the analysis of the architecture
6
Chapter 1. Introduction
of a software system entails the possibility of misunderstanding architectural documents and forbids any formal reasoning. Standard commercial architectures, such as Microsoft's OLE/ActiveX or CORBA/OpenDoc, lack of any formal support, making software development a handcrafted activity where the quality of the resulting product relies only on the ability of the programmers. Within those frameworks, words like components or interoperability have dierent meanings according to the particular model and functionalities provided by the environment. For example, the notion of object or component in COM/OLE is substantially dierent from the one accepted in CORBA environment (and from the one provided by the most common object oriented languages). The typical description of an ActiveX component consists of a textual description augmented with a formal part describing the number and the types of the parameters. The only possibility for the customer to verify the behavior of the component is based on trial and error until he gains con dence enough to use that component in the required way. A formal approach could be useful to clarify the relationships among the dierent models and to ensure that dierent components can integrate and successfully collaborate within the same application.
Formal Methods and Java Since its appearance, the Java programming
framework has strongly in uenced both the academic and commercial world, attracting a lot of interests from researchers and software developers. In large part its success has been determined by the features it incorporates, like concurrency and distribution, which made Java the language of choice for the development of Web applications. Formal methods have played only a marginal role in the planning and development of the Java framework. The Java programming language and the Java Virtual Machine are described only by the reference manuals provided by Sun [GJS96, LY96], which give a detailed description of both the language and the byte-code to which each Java program is translated. In the absence of a formal
Chapter 1. Introduction
7
notation, all the fundamental features of Java and its integrated framework are exposed in a descriptive way, generally with a number of examples and tutorials. Since their rst release, a number of bugs and ambiguities have been discovered and a list of the known and still unresolved bugs is maintained at the Java web site (and is continuously updated). Security, which is one of the most important points of the Java language, has been broken by several attacks which exploited misleading interpretations or underestimated features of Java descriptions, leading to insecure Java implementations [DFW96, Sar97]. A formal semantics both for the Sun's language and for the byte-code executed by the Java virtual machine, is the rst step to get assurance on the behaviour of a Java application. The lack of an ocial semantics has prompted recently several works to provide a de nition of a formal semantics for Java itself and its virtual machine [DE97b, Sym97, Coh97]. Also the extensions of Java like Java RMI, Java Beans or Java JDBC, are presented using no formal notation. As reported in the JavaBean Sun's paper [Sun96a]: \we want to avoid using any separate speci cation language for de ning the behaviour of a Java Bean. Rather we would like all of its behaviour to be speci able in Java". As a result, the lack of a formal notation for the development of a Bean and the lack of an ocial semantics for Java, makes it dicult to reason and to get enough con dence in the correct behaviour of Bean based applications, and more in general in applications exploiting the extended framework provided by Java. Sun is supporting the use of Java by releasing a number of integrated frameworks and products which cover a large number of application elds. The Java Web page at the Sun site (http:java.sun.com) is continuously updated with novel Application Programming Interfaces for dierent elds such as JavaMail for mail systems, to provide a platform independent framework to build Javabased mail and messaging applications, JDBC for database access, to provide a uniform interface to a wide range of relational databases, Java Transaction to
8
Chapter 1. Introduction
develop applications for distributed transaction systems, JavaMedia to integrate multimedia within Java applets and applications. Furthermore, hardware systems totally based on Java and JVMs embedded into small electronic devices (Java Card) are being developed and will become available in the next future. While the use of Java spreads among software developers a formal support could help to show properties of the implementations augmenting the con dence of the customers. Formal contracts and speci cations should be used to discover in advance bugs and errors which could compromise the correct behavior of the nal applications.
1.3 The approach The goal of our work is to provide a formal notation for the speci cation and the veri cation of software components and a methodology for the design of software architectures for Java-based applications [AG96]. Our approach entails the support of formal notations and tools at all dierent abstraction levels which the speci er and the designer are required to reason about during the software process. Starting from the recognition that the architectural level of description is a fundamental point in the software development process during which the basic structure of a system is outlined in terms of its constituting elements, we split the problem of giving a complete speci cation of a system by reasoning separately on its components and on their composition. We introduce an algebraic style of speci cation for modules written in Java, and explore the use of such a notation for the de nition of components to be successively employed in architecting of concrete applications. We also provide an architectural language which exploits the components descriptions based on the previous approach and provides a formal framework where it is possible to state and analyze system global properties by reasoning
Chapter 1. Introduction
9
on the behaviour of a system as resulting from the composition of the behaviour of its single parts and from their interactions. We give a rigorous foundation to both the component and the architectural notations, by providing a formal semantics for the Java programming language through the de nition of a transition system which models the execution of a Java component and provides a powerful framework to analyze its behaviour. The basic mechanisms of Java are investigated and formally de ned, paving the way for the formal evaluation of Java programs. The semantics is then exploited to start a veri cation process for Java components, such that their properties can be formally proved.
1.3.1 A Notation for Components Ljala is the notation we have developed to formally specify Java objects and components. It belongs to the Larch family of speci cation languages which consists of the Larch Shared Language (LSL) and a collection of several Larch Interface Languages (LIL), each tailored for a particular programming language [GHW85]. The peculiarity of Larch with respect to design speci cations is the \two tiers" (or layers) approach it uses. The lower tier is the Larch Shared Language, an algebraic speci cation language which de nes the mathematical abstractions used in the other tier, which is the behavior interface language in which predicates on pre and post condition over the execution of the operations are de ned [GH93, Win87]. We use Ljala for a basis of our methodology, since its "two tiered" approach is a valid aid for bridging the gap between speci cation and concrete implementation of software components. The mathematical vocabulary provided by the rst layer can be used to de ne the abstract entities constituting a speci cation, while the modules written in the second layer re ect the target programming language, making it possible to de ne the functional behavior of a Java program. At the moment there are about 14 Larch Interface Languages being developed for as much programming languages. Our work is strictly related to works on
10
Chapter 1. Introduction
GCIL [Ler91] and Larch/C++ [CL94a] where a Generic Interface Language as a generic basis for the de nition of new concurrent languages and an interface language for C++ have been proposed respectively. A Java Modeling Language has been recently proposed in [LBR98] for the design of Java classes and interfaces, combining the Larch with the Eiel [Mey92] approach to speci cation. The algebraic speci cation language CASL, Common Algebraic Speci cation Language [CoF98], has also been provided with features to describe the modular structure of software systems under development; architectural speci cation in Casl provide both speci cations of the required component modules and a description of the way in which these modules are to be combined.
1.3.2 An Architectural Language An architectural language provides a formal framework which guides the development of applications through the composition of preexisting components and in which it is possible to de ne and reason about properties of system being developed [SG96]. We start from the de nition of generic components which can be adapted and re ned to satisfy the particular requirements encountered, exploiting the modularity supported by Ljala notation. The behavior of such components can be described and analyzed individually in each Ljala module while their interrelationships can be de ned in con guration modules which are the unit of speci cations in our Larch Architectural Language. In this way we have another level of formal design which allows an overall vision of the system as formed by interacting components and puts in evidence global constraints and behavioral properties. The formalization of the design of modules written in Java should ease the development and the reuse of previous experience for the concrete building of speci c instance of a system. Recurrent components and connectors can be de ned and their abstract properties exposed in order to provide the designer with well speci ed and functioning modules to be easily combined together.
Chapter 1. Introduction
11
A simple parser for Ljala speci cations has been developed; we plan to extend this tool to make it possible to perform static semantic checks. Finally, our notation can be exploited for the modeling of reference architectures such Java Beans [Sun96a] which are more and more used and are becoming a standard for software programmers. The resulting formal framework provides a valid guide for the design of system based on those software platforms [Cim99].
1.3.3 A Semantics for Java objects Formal analysis of Java programs (or components) must be supported by a rigorous model of the executing environment. The de nition of a formal semantics for Java, provides the necessary framework for the rigorous analysis of programs and the means by which correctness of implementations may be established [DE97b, SA97, BS98]. We de ne a reduction semantics for the Java programming language such that dynamic behaviour of programs can be analyzed. Furthermore we de ne a veri cation methodology based on such a semantics in order that correctness of implementations can be showed w.r.t. the Ljala speci cations. The nal goal of such process should be a catalogue of software components factory, where each product is provided with its own speci cation with (formally proved) properties and the relative correct implementation ready to be used in the design of complex applications.
1.4 Summary of contributions The main contributions of our work can be summarized as follows:
a formal methodology to design software components and describe software architectures combining such components;
study and de nition of a formal semantics for a subset of the Java programming language;
12
Chapter 1. Introduction
an algebraic notation for the description of Java components; modeling of a case study of reference software architecture (Java Beans).
1.5 Structure of the thesis The thesis is organized as follows: - in chapter 2 we survey some current software composition techniques; - in chapter 3 we introduce both the component model and the speci cation language which we use for the modeling of Java applications; - in chapter 4 we introduce a notation for the description of system architecture and show its use for the modeling of a simple application based on JavaBeans; - in chapter 5 we de ne a reduction semantics for the object oriented kernel of Java; - in chapter 6 we extend the semantics to deal with concurrency; - in chapter 7 we introduce a methodology for the formal veri cation of the implementations of Java modules with respect their Ljala speci cations; - nally, in chapter 8 we draw some conclusions and trace future work.
Chapter 2
Background 2.1 Introduction Decomposing a large problem into more easily tractable subproblems is a wellknown and useful technique applied in many disciplines. In the context of software development, composition mechanisms such as macros, subroutines, modules and packages are usually supported by traditional programming languages, providing useful abstractions for software designers. However, those abstractions are not sucient for software designers facing the increasing complexity of modern software systems [Nie95]. Open-ness and distribution are common characteristics of modern applications designed to exploit the underlying evolving technology. The heterogeneity of both hardware and software and the rapid changing of requirements which are to be satis ed, yield evolving systems which require complex management policies [Agh98]. A compositional approach applied to system design, allows speci ers to factor out complex applications in terms of simpler computational elements with clear advantages for system design, veri cation and reuse. [Cle96, SG96]. Software composition involves several elds of research, sharing a common vocabulary of notions and concepts coming from programming languages, (Module Interface Languages, Interface Description Languages and Coordination Languages) or from other techniques for software development (architectural design,
14
Chapter 2. Background
component based development, design patterns and object-oriented software development). In this chapter we will overview some background on software composition, showing the relationship among those dierent techniques. We then introduce our component model and a formal framework for the speci cation and the design of software systems.
2.2 Object Oriented design Object oriented design has been one of the most used technologies in software design during the last decade. Objects represent abstractions for concrete problem domain entities. The encapsulation of both data representation and behaviour, allows separation of implementation and interface for any object, while classes represent abstractions for groups of objects sharing common behavior. The mechanism of inheritance allows for reusing the speci cation of a class when de ning a new class and oers a classi cation relation between objects. Each class can reuse the behaviour of its superclass oering the same operations on its interface and adding or rede ning opportunely new methods. Polimorphism through inheritance allows dierent objects to be able to respond dierently to the same message, making the message passing interaction mechanism between objects more powerful than the function call mechanism provided by other non object oriented programming languages. The Object Oriented paradigm is not sucient alone to deal with architectural issues. In the context of component based development, object oriented technology fails to address all the needs of software designers [PS96]. Object oriented languages emphasize programming over composition, that is, they are concerned more with the functional rather than compositional aspects of a system [Nie95]. The object model reduces all the possible complex interactions among objects to message passing. Object oriented design can be thought of a particular architectural style in which all components are objects and all connections are simple association or aggregation.
Chapter 2. Background
15
2.3 Architectural design Software architecture has recently become an autonomous eld of research in software engineering, attracting a lot of interest from both the academic and industrial world [SG96]. The importance of software architecture is con rmed by the amount of work and conferences focused on this eld [GTP95, Wol97]. On the other hand, software architecture research has potentially a deep impact on the market by in uencing fundamental aspects (and cost-eective features) such as reuse and maintenance. While the basic idea to decompose a large system in simpler computational elements is not novel, software architecture oers a new perspective to software developers, providing abstractions to describe and make intelligible the structure of complex systems. Ideally, an architectural document describes a system in terms of its constituting elements and should allow reasoning on high-level design issues such as global organization, interaction protocols, scaling, performance, and synchronization [GP95].
2.3.1 Abstract model of Software Architecture A formal basis for the study and the de nition of software architecture as a well founded discipline has been laid during the last decade independently by two groups: Perry and Wolf and Shaw and Garlan. Perry-Wolf ([PW92]), consider the software architecture of a system as a triple: Architecture = f Elements + Form + Rationaleg where - elements are the components (processing, data, and connecting); - form is the complex of properties and relationships constraining both the choice and the placement of the elements;
16
Chapter 2. Background
- rationale is the motivation for the particular choices made for element and forms. Garlan and Shaw de ne the software architecture of a system as [SG96]: \The structure of the components of a program/system, their interrelationships, and principles and guidelines governing their design and evolution over time." The two models have many similarities recognizing rst class entities in process, data and connecting elements, otherwise referred to as components and connectors. The main distinction is the rationale, which is not considered by Shaw and Garlan and the approach to de ne style and architectural instances. In Perry and Wolf, both are de ned as a collection of constraints limiting the choice and the placement of computational elements. For Shaw and Garlan, architectural instances are instead de ned through con gurations, while styles are given by a set of constraints respect which each speci c instance can be tested for conformance. Several de nitions of software architecture have been given in literature (see [GAACB95] for a survey) presenting slight variations from the preceding models and incorporating dierent features such as stake-holder needs within the description of a system architecture. Throughout the rest of the dissertation we will adopt the Shaw and Garlan's model which we feel closer to a practical use of architecture within the software development process. The focus of software architecture is on the overall structure of a software system exposed in terms of con gurations of interacting computational elements. Dierently from other compositional techniques commonly used in programming languages, such as packages or module interconnection languages, architecture is concerned with large grained composition and components interactions at a higher level of abstraction [GP95, SG96]. Any notation for the description and analysis of architecture must then provide [All97]:
Chapter 2. Background
17
some descriptive capabilities, to de ne the components composing a system and the interactions among them often captured in a con guration;
some analytic capabilities, in order to allow the designer to describe and
show the properties of the system being constructed. Both single instance of a system or a style should be analyzed to determine if the requirements are satis ed;
some style speci c description capabilities, in order to describe family of systems sharing the same characteristics.
2.3.2 Architectural style A style is an architectural abstraction for families of systems sharing common characteristics, such as a common vocabulary of components and of interaction patterns, and properties related to the particular topology of the system [SG96, AAG95]. When a system is built conforming to a prede ned style, we know that some speci c constraints on the structure of the system must be satis ed. For example, a pipe- lter system is de ned as a graph of stream transformers, in which components are lters which act on the ow of data, and connectors are pipes which merely transfers data among elements. The use of architectural styles has a number of bene ts [MKMG97] for software design, such as the reuse of both design and code. Well known routine solutions with well de ned properties can be re-applied to new problems sharing implementations for the invariant parts of the architecture. Moreover, style speci c analysis can be performed for any instance conforming to the style. The notion of style in architectural design extends the possibility of reuse of a single component to particular patterns of interacting elements.
18
Chapter 2. Background
2.4 Design Patterns The technique of design patterns aims to classify \best practice" solutions to problems recurring in the development of applications, in order to help and guide software builders. They can successfully exploit prior experience in the solution of a given design problem by applying the right pattern of design [MKMG97, GHJV95]. The well known book by "the gang of four", [GHJV95], is a catalogue of most used design patterns, each classi ed with a text template, which illustrates the motivation, the condition for the applicability, the structure and other information, and with class and object diagrams based on the OMT technique. In [Lea97a] a number of constructs and techniques to solve common concurrent design problems are presented and implemented in Java. An explicit recognition of the design problem to be solved and of the usage of the required pattern is necessary for the appropriate application of the design pattern. The complexity of design patterns ranges from solutions to concrete programming problems to solutions involving the overall organization of the system. The usual way, however, in which design patterns are described, is a mixture of informal and formal notations with annotated examples written in a particular programming language or in pseudo-code. The main problem is that the problems of composition of objects are solved without the support of an high level notation. This leads to a mixing of architectural issues and computation activities. The design patterns technique supports and enhances object oriented design giving the designer the capability to describe complex interactions between groups of objects. The principles underlying design patterns, however, are not strictly related to object oriented design. Patterns aim to capture design expertise related to a particular problem in a speci c context, and are in this sense more related to the notion of architectural style. The main distinction between a design pattern and a speci c style is the level of abstraction: a style provides a designer with a well de ned vocabulary and framework to build and analyze architectural
Chapter 2. Background
19
instances conforming to the style, whereas a pattern focuses on the solution of a smaller or more speci c problem, such as how to implement a particular design mechanism in a concrete programming language [MKMG97, Lea97a].
2.5 Component-based software development Recently the development of applications through the re-assembly of reusable software components has emerged as a highly productive way to construct custom applications. Component oriented programming has been described as the natural extension of object-oriented programming to the realm of open and distributed systems [WBS97, OH97] The complexity of components ranges from simple graphical widgets such as buttons to full size applications such as word processors or spreadsheets. In general, component based software is used to refer to a software model consisting of a set of programming guidelines which a designer can use to dynamically combine software components when building an application. A component based software model consists typically of three elements:
Components, which are software objects including some algorithmic logic. Containers, which are software objects used to assemble components and
to provide a context in which components may interact. Containers can be nested and are referred to sometimes as shells, frames or forms.
Scripting mechanisms, which provide the ability to initiate and guide interactions between components; scripting tools may exploit common programming languages such as C++ or Java, or script languages such as Tcl/Tk or JavaScript.
Furthermore, a component based software model must provide a number of services which are mandatory for an ecient construction of applications. When a component is linked at runtime, mechanisms for the identi cation of such a component are required such that other components learn how to interact
20
Chapter 2. Background
with it. This process is often referred to as the registering or publishing of the component interface with the framework. Persistence is related to the need to store state information about components. Event handling is the most common means of communications among components. When a component raises an event, the framework is responsible for delivering correctly the message to the right object. Events may be generated by the system or by other components. Other facilities, related to a particular component model adopted, include control of the visual appearance and mechanisms to support components to expose their properties and interfaces, such that development tools may be easily employed to quickly assemble components in an application. Commercial platforms like ActiveX, Open-Doc, and Java-Beans implement these features in dierent and often (voluntarily) incompatible ways. Furthermore, a number of programming environments, such as Visual Basic or Delphi, provide large libraries of largely used tools and functionalities (such as window widgets) which are referred to as components. The main drawback of those systems is the lack of any support for the description of their composition; they only provide pieces to be easily combined to develop an application with a reduced eort.
2.5.1 CORBA/OpenDoc CORBA (Common Object Request Broker Architecture) [Obj95] is a proposal of the Object Management Group, a worldwide consortium composed by several industries and research groups, for the de nition of a standard architecture for object interoperability across multiple languages and dierent operating systems. At the core of CORBA there is the ORB (Object Request Broker) which mediates the communication between (distributed) objects. The ORB is responsible for nding the object implementation for the requested operation and for performing any needed additional preprocessing before the service request is accomplished. One of the main goal of CORBA project is to achieve distribution transparency, allowing clients to communicate with server objects independently
Chapter 2. Background Object Services
21 System Services
Appl. Services
Domain Services
Object Request Broker
Figure 2.1: CORBA framework of their respective physical locations. Any ORB must provide a number of services at dierent levels of granularity ( g. 2.1):
object services which address object interoperability among dierent languages, interfaces or platforms;
system services which provide basic support for distributed services such
as naming and trading functions for managing, querying and navigating through object name spaces;
application services which allow the creation of application as frameworks of collaborating components;
domain services which provide domain speci c services for specialized application in dierent elds like health or nance.
Language independence is ensured by the adoption of an Interface De nition Language syntactically similar to C++, which is a declarative language by means of which objects tell their potential clients what operations are available and how they should be invoked. An Interface Repository is another important component of the ORB, providing access to the available collection of object interfaces written in IDL. Any object implementation need then a Basic Object Adaptor to communicate and interact with an ORB. Figure 2.2 shows the steps needed to obtain a running CORBA object. Starting from an IDL le which
22
Chapter 2. Background
contains the IDL de nition of the server object interface, a precompiler (for example a idl2java compiler, if Java is the target programming language) produces languages skeletons for the implementation of server classes. Then code for the real implementation of the classes must be supplied while stubs are automatically generated. IDL Program
Precompiler
Skeletons
Add impl. code Interface Repository
Object Adapter Compiler
Client IDL Stubs
Client
Server IDL Skeletons
Object
Implement. Repository
Implementation
Server
Figure 2.2: Steps to create running CORBA objects Built on top of CORBA, OpenDoc provides a simple and powerful document model for CORBA objects, integrating three other proposal developed by IBM (System Object Model) and Apple (BENTO and ICA). OpenDoc (as well as Microsoft's ActiveX model, which we see later) focuses on the concept of document as opposed to that of application in developing reusable software. Each document is composed of a number of parts, each associated with a specialized component
Chapter 2. Background
23
which knows how to retrieve it in a transparent way for the user. The implementation model for a document consists of storage, data transfer, layout, scripting. Storage facilities give the static document structure which consists in a hierarchy of levels supporting both the descriptions of the parts contained and history and version controls. Data transfer and layout facilities involve the treatment of component mobility and display. Finally, scripting provides the basic mechanism to add functionalities to documents, turning them from passive entities into active intelligent entities capable to modify and adapt their behavior according to the interactive dialogue with the user. CORBA has rstly introduced basic concepts and technologies for achieving interoperability among distributed and heterogeneous objects. The standardization work and the discussion on the proposed model shed light on several issues related to object interoperability. CORBA proposal may be however superseded by second generation systems like Java or by Microsoft.
2.5.2 COM/OLE/ActiveX COM is the Component Object Model proposed by Microsoft to specify component services, while OLE (Object Linking and Embedding) speci es system and application services, providing the Microsoft strategy to make MS Windows migrate towards object oriented technology. COM objects, usually called Windows objects, dier from the traditional notion of objects oered by other programming languages. A Windows object has no associated state and is de ned by its set of interfaces, each one composed by a collection of function pointers. OLE supports containers which display objects and accept commands for them, while the processing of the object is demanded to server application which the object is associated with. Containers and servers are speci ed as collections of interfaces which contain the set of operations that can be applied to an object via its server. Objects may be integrated within a compound document in two dierent ways, through their embedding or linking. Embedded objects are owned by the
24
Chapter 2. Background
container application while the server application retrieve and process the object. Linked objects can be shared among several containers. ActiveX is the Microsoft's term for its initiative aimed to enrich COM/OLE framework providing a document model for WWW applications. The ActiveX component model is composed of three principal parts: ActiveX Controls, Scripts and Documents. ActiveX Controls are interactive objects which support the insertion of software components into Web documents. Controls are language independent, i.e., they can be written in a variety of common programming languages (such as Java, C or Visual Basic), and a growing library of Controls is available to enrich HTML documents. ActiveX Scripts controls the behavior and interactions of ActiveX control within the same container and are embedded in HTML code and compiled when the document is read by Internet Explorer. ActiveX Documents integrate stand-alone applications like Excel into Web documents. Similar to Netscape Navigator plug-ins, ActiveX Documents register themselves as handler for a particular type of data, so that whenever the browser shows a page containing data of that speci c format, the corresponding application is launched. For example, a spreadsheet created in Excel can be opened directly by Internet Explorer.
2.6 Java The development of Java begun in the early 90s at Sun Microsystem. The goal of the Java design team was to develop a simple, compact and easily portable runtime system able to run software on consumer electronic devices. The starting point for the project was the C++ language, but the realization of the inadequacy of this language to cope with a number of required features caused the development of a new language initially called Oak and later renamed as Java. The potential of the new language was later recognized by Sun which adapted the original project to the Web technology building up an environment useful to develop both Internet and intranet applications.
Chapter 2. Background
25
The success of Java is in large part related to its revolutionary impact on World Wide Web. The rst version of the language was released contemporarily with the announcement of Hot-Java, the rst browser able to execute Java applications. Sun introduced the possibility to download remote code (\applet") which can be executed on the local machine where the browser is running, enormously increasing the interactivity of a Web document. At the moment almost all the Web browsers incorporate a Java kernel in order to be able to execute applets and Java has become the reference language for developing Web applications. Furthermore Java chips and Java-dedicated workstations are on the way and will in uence probably the next future of computer market.
2.6.1 Java characteristics Java shares many characteristics with C and C++, inheriting much of their syntax and semantics. However Java is mainly pervaded by requirements like compactness, portability and security, which have been taken into account from the beginning during the development of the language. These requirements are behind several dierences from C++ and other object oriented languages. To achieve portability of applications, Java programs are compiled into a bytecode format which is independent of the particular platform on which the Java compiler was running. Then, byte-code can be transmitted across a network and executed by a Java Virtual Machine running on the local host. This possibility to execute remote code introduces the need of severe checks to be performed by the local runtime system in order to prevent intentional or accidental attack to the integrity of the system where the Java interpreter is running. To improve security and safety of the runtime system, a strict type model and several runtime checks control and discipline resource access. In particular, in Java all object are strongly typed and are part of a singly rooted hierarchy of types (with Object as base class) such that they have a common interface. The type is determined statically and checks are performed during compilation, even if dierent types can be dynamically assigned at runtime. A byte code veri er
26
Chapter 2. Background
also ensures, before execution, the correctness of the code, by checking structural constraints and performing data- ow analysis. Furthermore, problematic features of C++, like pointer arithmetic or explicit memory management have been excluded since they could expose the Java system to potential unsafe behaviours. The syntax is strictly and accurately speci ed in the reference manuals both of the Java language and of the Java Virtual Machine. On the contrary, implementation issues are largely overlooked, in order to make the language independent of the particular architecture where the program is running. For example the size and the value ranges of the built-in types are de ned once for all in the language speci cation. Java object model and JavaBeans component model provide a language and an application framework better designed and integrated than earlier system [Weg97]. While Java model integrates within CORBA [OH97], even if the canceling of OpenDoc by Apple could be a prelude to the migration of OMG toward JavaBeans component model, the controversy with ActiveX model is animated by strong company interests. The battle between Sun' and Microsoft's component technologies will determine which of the two companies will acquire a leader position in the rapid evolving eld of Internet and Intranet applications development.
2.7 Discussion Component-based and architecture based software design are rapidly emerging technologies which present exciting and promising directions in software development toward the goal of a true engineering discipline for software [All97]. Extending the Object Oriented paradigm and building a set of powerful abstractions to model the structure of software systems, component oriented programming and software architecture languages meet designer needs for new tools and methodologies to face the new challenges oered by the development of open and distributed systems. Despite an increasing interest by both the academical and
Chapter 2. Background
27
industrial world, and a number of success stories in the application of those new technologies, a systematic integration of the architectural design in the software process is longer to come. Current practice relies on informal architectural descriptions and component frameworks which make it easy to develop complex applications with a low man-power eort but which lack of a stable component model and support to describe and manage composition. The dream of a software component industry is old and so far has remained a pipe-dream [Szy96]. Object oriented programming is a foundation technology for component industry, but is not enough. As evidence of this, the most successful component market is a niche market created by Microsoft's Visual Basic [ViB92] which involves no object oriented programming language either. As stated in [MT98]: \The current technical problems blocking software compositionality in practice could bene t from formal foundations providing clear semantics, new architecture and software composition methods, and better languages" [MT98]. In the rest of this dissertation, we will provide a formal framework where to develop formal descriptions of Java components and architectures. The interest for Java is motivated by the fact that it contains ecient answers to the fundamental questions which need to be addressed to exploit component software development. According to Szypersky [PS96, Szy96], Java can be called a component oriented programming language, since it provides polymorphism, information hiding, late binding and linking, and type safety. Furthermore, Java integrated framework greatly simpli es system interoperability requirements, by integrating interoperability within a single language and overcoming eciently the drawbacks of other approaches.
Chapter 3
Specifying Java Components 3.1 A formal framework for Java components and architectures The description of a system as composition of reusable and recon gurable components has a number of bene ts, coming from the possibility for the speci er to subdivide complex problems in smaller and easier solvable subproblems and to reason separately on organizational and functional aspects of a system. The architectural level of design deals with the high level organization of computational elements and their interactions. Our notion of software architecture is substantially based on the Shaw and Garlan's model [SG96]. We recognize components and connectors as basic elements of an architectural description. Con gurations combining the instances of those computational elements and de ning their interaction, provide a complete description of a system architecture. Complex applications may be thought as collection of components interacting via connectors, which collaborate to achieve a result. Once selected the architectural model we must also de ne a methodology guiding the design of components and a formal framework making developers able to reason about the properties both of the components and of the whole application. Component and connectors are completely independent entities which do not maintain explicit references. Interaction is achieved through the explicit point of
Chapter 3. Specifying Java Components
29 port
Algebraic spec.
Interface spec.
Figure 3.1: Schema of a component interaction with the external environment, which are ports in the case of components and roles for connectors. The generic schema of a component is given in gure 3.1. Each component is then speci ed supplying both an algebraic description of its internal state and a speci cation of the interface it provides to the external environment. The interface describes a boundary between the component and its environment and plays a very important role on the whole system speci cation [Lam89]. Each interface speci cation should:
de ne the possible interaction between a component and the external environment;
identify the initiator of the interaction. Behavioral speci cations are insucient to determine the kind of a system being speci ed, since dierent kinds of systems can exhibit the same observable behavior [Lam89]. The description of the functional aspects of each operation must be integrated with speci c interface information describing how the operation may be invoked, specifying for example for each function the number and the types of its arguments [Win87].
30
Chapter 3. Specifying Java Components
3.1.1 Components A component denotes an independent computational element which can be employed in the building of an application after an opportune integration with other constituting part of the system. According to [Nie95], a software component is an \abstraction with plugs", i.e., a component encapsulates both data and independent behaviour with a well-de ned way to interact with the external environment and the other components. A component instance can be a single object or a group of cooperating objects with a clearly de ned boundary to other components [PS96]. Objects inside a component are tightly interconnected, while interaction with the external world is relatively loose and, in our model, it must pass through the ports provided by the object. Controlling the component's interactions is necessary to reduce as much as possible the assumptions made on the external environment that typically limit the reusability of components in dierent applications. In this way a component acts as unit of abstraction which does not keep references to other components and delegates any form of inter-communications to the connectors.
3.1.2 Connectors Any application can be interpreted as a construction of software components which interact to achieve a result. If we want to single out the compositional features in software building and to support the description and the analysis of architectural con gurations, we must give an explicit speci cation of interactions between components [Agh98, All97]. Connectors then become rst class entities in the design of the system. Each connector is independent of the components to which it is attached, and they are unaware of the particular connector. The interaction occurs through the association among components' port and connector's roles. Several bene ts are achieved by explicitating the role of connectors in architectural design. First of all, patterns of interaction repeatedly occurring in an
Chapter 3. Specifying Java Components
31
architectural con guration can be reused and analyzed. Each property of a connector is valid for all the connector instances used in a system, for which both the speci cation and the code can be reused [All97]. Independence of components is increased, since connectors provide the boundary that de nes the expectation a component may have to interact with the external environment. Only a good decomposition allows to reliably construct (synthesize) or understand (analyze) a complex system. The coupling between units determines the extent to which the analysis of one unit needs to take properties of other units into account [PS96]. If units are tightly interconnected, as it occurs in unstructured systems, individual analysis of components is not ecient and a global view of the system must be considered. Connectors are not strictly necessary from a logical point of view: they could be regarded as particular types of components. From a methodological point of view, connectors match the abstractions which designers use to describe system architectures. They correspond roughly to the lines connecting the computational elements in the informal diagrams which usually provide the description of a system; formalizing their role in the overall design and providing them with a well de ned semantics, favors the understanding of the behavior of the system.
3.2 Ljala: a formal speci cation language for Java components In this section we present the notation we have developed for the formal description of Java components. The Larch Java interface language (Ljala for short), belongs to the Larch family of speci cation languages, developed by Guttag et al. [GH93]. These consist of the Larch Shared Language (LSL) and a collection of Larch Interface Languages (LIL), each tailored for a particular programming language [GHW85]. The peculiarity of Larch with respect to other speci cation languages is the \two tiers" (or layers) approach it uses (see gure 3.2). The kernel tier, language-
32
Chapter 3. Specifying Java Components
independent, is based on the Larch Shared Language, an algebraic speci cation language which provides a mathematical vocabulary de ning the properties of useful abstractions like sets, stack or other. The other tier, language dependent, is based on a behavior interface language in which predicates on pre and post conditions describe the eect of the execution of the operations on the state of a program module [GH93, Win87]. The advantage of such an approach is that separating the speci cations of abstractions from the speci cations of the state transformations, reuse and clarity are improved. The algebraic components can be easily included in dierent applications, since they do not depend on the particular state or model of computation or programming language. Having an interface speci cation language close to the target programming language makes the component designer able to reason in terms of language dependent issues and eases the task of the implementor.
3.2.1 Informal description Ljala has been developed starting from the design of Larch/C++ [Lea97b] with the modi cations necessary to support the novel features supported by Java, such as concurrency. An interface speci cation module describes the behavior of an operation by de ning the relation between the state in which an operation is invoked and
LSL Layer LIL Layer
= LSL library trait = LSL trait
= LIL module
= Includes = Uses
Figure 3.2: LSL and LIL layers in Larch speci cations
Chapter 3. Specifying Java Components
33
the state after the execution of the operation, through the de nition of requiresmodi es-ensures clauses. An implementation of an operation satis es the speci cation only if it produces the same state changes when it is invoked in a state that satis es the precondition. Since Java supports concurrency by admitting several threads of execution at once, we are interested in specifying systems composed of a set of processes which can invoke operations on a set of objects. Processes can run concurrently and concurrently invoke operations on objects; each process invoke sequentially operations. A single operation can be composed of a sequence of atomic actions which are executed in the right order and may be interleaved with the actions of other operations. Since the main purpose of the interface speci cation language is to specify the acceptable behaviors of objects, in this model, when considering each single object speci cation we distinguish between the system and the environment. The former consists of the object and its scheduler, the latter consists of the other processes invoking operations on the object. Synchronization conditions determining the correct activity of concurrent threads are handled in additional when clauses.
3.2.2 Overview of LSL The basic unit of speci cation in LSL is a trait which describes a collection of sorts which are non-empty sets of elements and operators which are functions manipulating such elements. A trait can be referred to by its name which is independent of the data abstractions and operators appearing within it. Sorts are declared implicitly by their appearance in operator declarations and are named by a simple identi er (such as Int) or by a simple identi er followed by a list of sorts enclosed in brackets (such as Set[Int]). Each trait is structured as follows. An introduces section lists the operators and de ne their signatures. An operator is a total function that maps tuple of values of its domain sort to a value of its range sorts. Every operator used in a trait must be previously declared.
34
Chapter 3. Specifying Java Components
Then in the asserts portion, equations de ne properties of operators stating equalities among terms. The assertion are rst order formulas built up from variables and operators declared in the trait as well as from the built-in operators and quanti ers provided by LSL. The implies part of a trait is used to de ne optionally consequences of the assertions. LSL provides some constructs to strengthen the equational speci cations. The partitioned by clause asserts that a list of operators are a complete set of observers for a sort, i.e., all the values of the sorts may be distinguished using those operators. Such clause adds a deductive inference rule to the theory. A generated by clause gives a list of operators which are generators of the sort, i.e., each value of the sort can be represented in terms of the listed operators. The clause provides an induction schema which can be useful in formal proof of properties of the sort. Finally converts clause following the implies section, list the operators which are fully de ned by the trait's axioms, optionally excluding the terms listed in an exempting clause. LSL provides also syntactic shorthands for common kinds of theories, such as enumerations, tuples and unions. The enumeration shorthand denotes a set of constants and an operator which enumerates them as in: Color enumeration of red, blue, green. The constructs tuple of and union of introduce shorthands similar to records and tagged unions found in programming languages. As example, LSL trait in gure 3.3, taken from [GH93], gives the algebraic speci cation of a stack. Each trait de nes a theory (i.e, a set of formulas) in multi-sorted rst-order logic with equality containing the trait's assertions, the conventional axioms of rst order logic and all their consequences. LSL trait have a loose semantic interpretation, i.e., the assertion in the theory follow only from the axioms in the speci cation, not from their absence. The advantage of loose interpretation
Chapter 3. Specifying Java Components
35
Stack(E,C):trait includes Integer
introduces
empty: -> C push: E, C -> C top: C -> E pop: C -> C
asserts C generated by empty, push 8 e:E, stk:C
top(push(e, stk)) ==e; pop(push(e, stk)) == e; implies converts pop,top exempting top(empty), pop(empty)
Figure 3.3: Trait for a stack is that theorems on incomplete speci cation remain valid when the theory is extended [GH93]. More formally, each LSL trait Tr de nes a set of function symbols F and a set of sorts Sort. Each function symbol in F has a signature declaring the sort of its domain and the sort of its range. A function symbol may have more than one signature (i.e., it may be overloaded). Let f be a function symbol de ned in the trait with domain D1; : : : ; Dn and range R, where n 0 and each Di and R are sorts in Sort; V ar is a set of variable identi ers partitioned by sorts in S . Let x be an element of V ar whose sort is S 2 Sort: Definition 3.2.1 A term is either of the form
x:S
or of the form
f(t1
; : : :;
36 tn ):R
Chapter 3. Specifying Java Components
where each ti is a term and n 0.
Definition 3.2.2 The sort of the value denoted by a term of the form x:S is S,
the sort of the variable identi er x. The sort of the value denoted by a term of the form f(t1; : : : ;tn):R is R, the sort of the function symbol's range.
Every term in Term and hence every value in V al has an associated sort from the set Sort. The sort can be omitted when writing a term if there is not the possibility of confusion.
; : : :;tn):R sort checks if the tis sort check and the sorts of the arguments t1; : : : ; tn and R match the domain and the
Definition 3.2.3 A term of form
f(t1
range, respectively, of a signature of the function symbol f. (A term x:S trivially sort checks).
We assume in the following that all terms in a speci cation sort check, i.e., that speci cations are syntactically correct and that all the assertions in the pre and post conditions are sort correct in the sense that the LSL operators conform to their signature speci ed in the traits [CL94b]. For common data structures like integers, sets, etc, Larch provides a collection of library traits, which can be reused to specify new objects or abstract values of some data type. LSL speci cations may be combined by using the standard include and assume constructs. The include clause allow the inclusion of the named traits in the current trait, incorporating in the resulting theory all the operators and assertions contained in the included traits. The assume clause has the same eect for the local theory, but the assumptions are discharged when the trait where the assume appears is included or assumed in another trait. During the inclusion, renaming is allowed by providing a list of changed names like mname1 for name2 for the included trait; all the occurrence of name1 are substituted with name2. LSL speci cations can be investigated to check for their consistency, the theory containment and completeness [GH93]. Each trait must be consistent, i.e, a
Chapter 3. Specifying Java Components
37
theory must not contain the formula false. Claims provided in the implies clause can be checked to be consequences of the axioms in the asserts section. The process of adding redundant information and to verify the claimed properties can be helpful in error detection. Completeness is not necessary for LSL theories. Speci cations may intentionally do not fully de ne their operators in order to avoid the introduction of irrelevant constraints on their successive implementations.
3.2.3 An interface language for Java Each interface speci cation language belonging to the Larch family is targeted to some particular programming language, including in its de nition issues and details speci c to the language. The basic structure of each interface language includes pre and post conditions for each function speci cation, introduced by the keywords requires and ensures respectively. The starting point to develop a new Java interface language is the de nition of a suitable syntax for speci cations, which is close to the grammar of the target programming language. In our case we are interested in the speci cation of modules and components written in Java; then we recognize classes as the basic unit of speci cation. Since in Java classes are the basic unit of programming, in Ljala each speci cation module speci es the interface and the behaviour of a class. The syntax of a class declaration is much the same of a Java class declaration, consisting of a class header and a body. The header denotes the modi ers and the name of the class as well as possibly its inheritance relationship with other classes and/or interfaces through the extends and implements clauses. Fig. 3.4 shows the application of Ljala to the speci cation of a bounded counter. The body of a class may contain an uses clause which de nes the traits that are used in the class providing the vocabulary to specify its behavior. An optional invariant clause speci es a property that must be true for all objects of the class. The predicates speci ed in the invariant restrict the space of the abstract values for the class. For example, for the Bcounter class speci cation, the invariant
38
Chapter 3. Specifying Java Components
public class BCounter f uses BCounterTrait; invariant value(self) Client Isconnected: Client -> Bool IsValid: Client -> Bool
asserts
8 c: Client
IsValid(c) == size(c.comp.inports) =1 ^ size(c.comp.outports) = 1
Figure 3.13: Trait for a Client component belonging to the component. Exchange of data occurs by opportunely modifying the stream of data on the input and the output port of the server. As speci ed in gure 3.17, a socket connector is constructed specifying the name of a host and the number of the port used for the connection. Java socket model, uses a connection-oriented protocol, meaning that after the connection is established, the client and server applications can send data back and forth, till the communication is terminated. The meaning of the interface speci cation modules are a collection of Java code les which satisfy their speci cation [Lea97b]. A possible implementation of the connector is shown in gure 3.18. Once a connection is made, input and output streams can be retrieved with the methods getInputStream and getOutputStream provided by the Socket class.
54
Chapter 3. Specifying Java Components
Server:trait
includes component,
Queue(data, inputstream) Queue(data, outputstream); Server tuple of comp:component, inputs: inputstream, outputs:outputstream
introduces
Initserver: -> Server Isconnected: Server -> Bool
Figure 3.14: Trait for a Server component The write() and read() methods are used respectively to send or receive data. The connection can be terminated by invoking the close() method.
3.5 Discussion The decomposition of complex software systems in a collection of easy combinable computational elements with well de ned responsibilities has a number of bene ts in a reuse-oriented development process. In our approach, each component speci cation integrates both the description of its interface and its functional behavior supported by an algebraic model in which a more abstract description can be given. Those descriptions may be used as the basis for the analysis and as a guide for the designers which have to produce the implementations of the components and to integrate the dierent parts of the system to work together. Dierently from other approaches based on very abstract notations such as Z [AAG95], CSP [AG97] or the -calculus [MDEK95], Ljala notation achieves an acceptable compromise between formality and practice, providing at the same time both a formal framework where it is possible to reason on the system prop-
Chapter 3. Specifying Java Components
55
socket: trait
includes connector,
Queue(data, inputstream) Queue(data, outputstream); socket tuple of conn:connector, inputs: inputstream, outputs:outputstream
introduces
Initrsock: -> socket Initinputstream: -> inputstream Initoutputstream: -> outputstream IsValid: socket -> Bool
asserts
8 r: socket
IsValid(r) == size(r.conn.inroles) =1 ^ size(r.conn.outroles) = 1
Figure 3.15: Trait for a socket erties, and an easy way to re ne a speci cation into an implementation. In eect, the overload on the development process due to the formalization eort has to be balanced by the bene ts gained in terms of clearness of the design and analysis capabilities oered to the designers. This is particularly true for reusable software components, since the eort to write formal speci cations is largely repayed from having complete models which ease their reuse in the building of new applications. On the other hand, Ljala can be used as an \annotation" language [GMP90, LBR98] for Java classes providing a powerful means to add formal documentation to existing software. Documenting class libraries, frameworks and Application
56
Chapter 3. Specifying Java Components
public class Serverf uses server; public void setup server( Int port)f requires : Isconnected(self) ^ port 2 self.comp.inports; ensures self' =Initserver;g public data get(Int port)f requires Isconnected(self); when : self ^.inputs = empty; modi es self; ensures result=head(self ^.inputs) ^ self'=set inputs(self ^, tail(self ^.inputs));g public data write(data d,Int port)f requires Isconnected(self); modi es self; ensures self'=set outputs(self ^, append(d, self ^.outputs));g
Figure 3.16: Speci cation of a Server component class Programmer Interfaces (in the next chapter we will apply our methodology to the JavaBeans framework [Sun96a, Cim99]), Ljala formalism and, more in general behavioral interface languages, provides a way to construct practical and eective formal speci cations. Such a formalization is largely worth the eort, since components which are already implemented and debugged are more likely to be reused [LBR98]
Chapter 3. Specifying Java Components
public class rpc sock(String host, Int port)f uses socket,String; public void setup socket(string host,Int port)f ensures self'=initsock ^ self'.inputs = initinputstream ^ self'.outputs = initoutputstream;g public void send data(data d)f modi es self; ensures self'=set outputs(self ^, append(d, self ^.outputs));g public Byte get data()f modi es self; ensures result=head(self ^.inputs) ^ self'=set inputs(self ^, tail(self ^.inputs));g public void disconnect()f modi es self; ensures self'.inputs = empty ^ self'.outputs = empty;g
g
Figure 3.17: Speci cation of a socket component class
57
58
Chapter 3. Specifying Java Components
f
public class rpc sock(String host, Int port)
f
public void setup socket(String host,Int port) Socket s = new Socket(host,port); Inputstream in = s.getInputStream();
g
OutputStream out = s.getOutputStream();
f
public void send data(data d)
g
out.write(d);
f
public Byte get data()
g
in.read();
f
public void disconnect()
g
s.close;
Figure 3.18: A Java class implementing a socket
Chapter 4
Specifying Architectures of Java Components 4.1 Introduction As discussed previously, components (and connectors) are modeled in our framework by speci cation modules based on LSL for the declarative part and Ljala for the behavioural part. In this chapter we introduce a notation to describe the architecture of a software system, namely how components and connectors can be composed. To de ne any interrelationship between components and to give a description of the overall system obtained assembling its components, we need a further level of speci cation. We propose a Ljala Architectural Language, which can be used to specify the structure of a software system in terms of the con gurations of interacting Ljala components. Such a notation enables a designer to describe a particular system, as well as a family of related systems conforming to a particular style, (pipe lter for example), stating particular or general properties which any instance must meet. On the other hand, a formal description should provide means to support analysis of the system, so that the functionalities of each single component, as well as of the overall system, can be tested. Such a description should support a re nement process which guides the implementor, from the abstract model to
60
Chapter 4. Specifying Architectures of Java Components
the concrete realization of a system, providing assurance that the implementation ful lls the requirements made in the abstract description. For this reason the most adequate level of abstraction must balance between formality and practice. By relying on Ljala, we can build a Java component ensuring that the process of re nement is respected. The aim of an architectural language is twofold: to describe the structure of the system and to trace the guidelines for implementing the system.
4.2 Con gurations At the architectural level of design, a system is described through its constituting elements and the interaction patterns occurring among them. Then a con guration module lists the instance of design elements which form our system, the Ljala modules which are used for the speci cation and the attachments between ports of the components and roles of the connectors. The structure of a con guration module is showed in gure 4.1. The con guration module has the task to de ne the topology of the system being built. The component and connector parts of the module serve to name the instance of the components and the connectors, respectively, used for the description of the system. For each type a trait must have been provided. The attached part lists the connections among components and connectors. Notice that each component may be reused in the same system by de ning multiple instantiations and opportunely connecting their ports through the connectors constituting a system. Additionally, functional properties may be added to describe and constrain the system behavior. Considering the client server example in gure 4.2, we have an instance for each component and connector we have de ned, and state inputoutput connections between rpc connector and the two components. We attach the in role of the rpc connector with the outport of the client component while the out role of the connector is attached to the input port of the server.
Chapter 4. Specifying Architectures of Java Components
system-name:con guration component: list of component instances connector: list of connector instances attached: list of connections among ports and roles behaves: activation rules properties: topological constraints
Figure 4.1: Structure of a con guration module c/s-system:con guration component: c1:client,s1:server; connector: r1:rpc attached: r1.conn.irole = c1.comp.oport; r1.conn.orole = s1.comp.iport;
Figure 4.2: Con guration module for a c-s system
61
62
Chapter 4. Specifying Architectures of Java Components
The implementation of a con guration module may be thought of as a main application module which uses the other components of the system and de ne their behavior when computation progresses. Our technique mixes the declarative and procedural approaches. The architecture theory resulting as collection of axioms constrains the global behavior of the system in terms of the behavior of its components. Pre and post conditions on the state rule the evolution of each component while computation progresses.
4.3 Semantics of con gurations A component (connector) in our formalism is represented abstractly by the theory derived from the associated trait, while its behaviour is expressed by the associated Ljala module. When components are connected together to build a complete system, the theory of the system is obtained through simple composition of the theories of the individual components, previous opportune renaming to avoid name con icts. Properties of the system exposed in the con guration module may constrain furtherly the system. Semantics of composition relies upon about the assumption that parts shared by the attachments clauses represent the same state component. The union of the theories associated to each component must be consistent and is de ned as the global theory of our architectural speci cation. Consistency of the speci cation ensures that the combination of the individual speci cations of components and connectors still make sense when put together and give a well-formed description of the system. The problem of composing speci cations in a general semantic framework has been studied by Abadi and Lamport in [AL93]. Similarly to our approach, they use a state based approach in which an execution of a system is viewed as a sequence of states, where each state is an assignment of value to system components, but to distinguish system from environment actions, they assume that the state changes are performed by some agents (partitioned into system agents and environment agents) instead of partitioning each component into input and output parts. The main result of
Chapter 4. Specifying Architectures of Java Components
63
their work, i.e., the composition principle stating that a composite system satis es its speci cation if all its components satisfy their speci cations, still remain valid in our case, since we consider only safety properties for the descriptions of the systems. The behaviour of an architectural con guration may be interpreted as consisting of the composition of the behaviours of each single component as speci ed by each Ljala module. Each part operates independently except when it needs to coordinate with other components; in this case its behaviour depends on the data exchanges which are administrated by the connectors to which it is attached. The evolution of the system is interpreted by looking at the state of the whole system as composed of the state of each single component. The whole system can be represented as a machine whose state evolves in response to external stimuli. In this sense a state transition is red as soon a method invocation is performed on a given component; the next state of the system is given by the description of the state modi cations given in the postconditions of the performed operation. If we want to look to components as active object we need to associate to each component a speci cation of its \recurrent behaviour". This can be done exploiting the behave construct provided in the con guration module. A number of behave clauses can be stated for each component in order to specify its behaviour. Each clause is composed by a precondition on the state of the component which acts as a trigger for the activation of the rule. If the preconditions hold, the operations described in the remaining part of the rule are enabled and can be executed by the object scheduler; each operation is then performed according the speci cation provided in the behaviour module of the component. Notice that behave clauses are substantially dierent from operations' speci cations. The meaning of behave clauses may be interpreted as the speci cation of the main part of the program implementing a component.
64
Chapter 4. Specifying Architectures of Java Components
C2
C1 K1
Con guration module
Conf. module
Figure 4.3: The hierarchic description of components
4.4 Specifying complex components Till now we have considered simple components (or connectors) which are speci ed by a single interface module using one or more algebraic modules. Since in our abstraction component functionalities may range from simple tasks (then implementable by a single Java class) to more complex applications obtainable through interactions among other elements, we allow con guration modules to be employed as components while designing other systems. Namely, one of the aim of an architectural language is to allow speci ers to construct composite components from both computationally simpler components and already composite components [MDEK95]. At the end of this process, the architecture of a system is described as a hierarchical composition of primitive interacting component instances each running independently (possibly on distributed computers). The nesting of con guration modules allows a hierarchical description of a system as shown on gure 4.3, where in the system formed by the two components C1 and C2 and the connector K1, the component C2 is described through a con guration module. In this case unattached ports and roles of the subsystem speci ed in the con guration module act as port and role of the complex component and can be attached to the other part of the system by providing opportune bindings in the attached clause.
Chapter 4. Specifying Architectures of Java Components
65
4.5 Description of styles An architectural style relates a family of system sharing the same types of components or connectors or the same kind of interactions or topological constraints. According to [AAG95], each style is de ned by:
Vocabulary of design elements; Con guration Rules or topological constraints restricting possible composition of elements;
Semantic Interpretation giving meaning to the composition of the design elements constrained by the con guration rules;
Analysis which are speci c to a a given style can be performed. The choice of a style when developing an application has a particular importance on the overall design activity. The main bene ts coming from the use of an architectural styles are in terms of design and implementation reuse. Routine solutions can be re-applied for the solutions of new problems relying on the set of properties which are de ned to hold for all systems conforming to the style. The characterization of a system in terms of a style gives great knowledge on its organization, since the vocabulary of computational elements and their interactions are well de ned and formal reasoning as well as specialized style speci c analyses are supported. We can describe an architectural style by de ning in the properties clause a series of property related to the style which the system is an instance of, following the approach to styles in [All97]. Properties are expressed through predicates involving the number, the disposition or the type of components and connectors employed in the designing of the system. The notation is based on rst order predicate logic and the following operators can appear in formulas: - Component, Connector, Attachments which return the set of the corresponding elements in the con guration, respectively;
66
Chapter 4. Specifying Architectures of Java Components
- Name(x), Type(x), Ports(x), Roles(x) which return the name, the type, the set of ports, the set of roles as de ned in the actual con guration for the element x. Abstract architectures can be in this way described and their properties possibly analyzed. For example, for a system which is based on a pipe- lter architecture the following properties should hold:
]Connector = ]Components ? 1
8c : connector Type(c) = pipe stating that the number of connectors employed in the system is determined by the number of component and that the only valid connectors must be pipes.
4.6 JavaBeans JavaBeans [Sun96a] extend the basic Java development package with component based application services. Each bean is a reusable software component which exposes its structure and design informations in order to interact with the containing document. Since beans are entirely written in Java, as a consequence of Java portability, beans are components which run everywhere, beeing free from any tie with platform speci c architecture. Beans provide facilities for the dynamic interaction with other beans or with other documents, collecting and manipulating runtime informations. In the ocial Sun documentation, a bean is de ned as a "reusable software component that can be manipulated visually in a builder tool". Usually tools may be web page builders as well as document editors willing to include beans as part of a compound document. Any bean individually may represent more or less complex structural elements of an application, such as a simple button or a slider or complex spreadsheets or database viewers. Usually but not necessarily, beans have a proper GUI appearance, such that they may be composed using a graphic application builder, such as the Beanbox provided by Sun.
Chapter 4. Specifying Architectures of Java Components
67
The beans' interaction paradigm ful lls the event-driven programming model. A bean acts as a source of events and maintains a list of listeners which are other objects potentially interested in the ring of particular events. Adapters are event listeners which are intermediate objects between the event source and the object willing to react to event occurrences. In Java events are modeled by a hierarchy of classes starting from Java.util.EventObject, and each event class has a corresponding event listener interface. Each event object may contain associated informations which is encapsulated in its state, such as, for example, the position of the mouse pointer when a button was pressed. The noti cation of an event is propagated from source to listeners by the invocation of the associated method on the target listener objects.
4.6.1 Modeling beans To develop a model for applications made up of interconnected beans, we must provide the formal model of a generic bean and of the generic connector employed. A generic bean obviously will be a component with particular structural characteristics. The connectors will be adapters which have the task to match events red by the source component and to forward them to the listener objects waiting to respond to such events. In gure 4.4, we give the LSL trait for a bean and model a simple bean implementing a button 4.6. A bean has a set of listeners which are the other components interested in the ring of the events. Each listener is noti ed of the occurred event through one of the output ports of the component; each listener is associated to a dierent output port. The call is then forwarded by the adapter to the destination component. As example of a typical bean, we describe the implementation of a Button. The Button class is provided by the Abstract Window Toolkit package of JDK1.1. Apart from functionalities involving graphics, each button has the capabilities to perform actions on the occurring of events such as mouse clicking. The clicking on a button with the mouse is associated with one instance of an event of type ActionEvent. When a button is pressed and released, the AWT sends
68
Chapter 4. Specifying Architectures of Java Components
bean:trait includes component, Queue(event,oport), Queue(event,iport), Set(listener,Listeners) bean tuple of comp:component, lis:Listeners
introduces
assoc: Listener -> Oport
asserts
8 l,l':listener assoc(l)= 6 assoc(l')
Figure 4.4: Trait for a bean the instance of an event to the button, by calling the processEvent method on the button. The component willing to perform some action whenever the button is pressed and released, should implement the ActionListener interface and register to receive events from the button calling the AddActionListener method. Then a Button will be a bean with a label string; we show in the gures 4.6 and 4.7 the trait and the interface module for a simple button, respectively. Apart from the constructors speci cation, the main actions of a button are the of adding/removal a potential listener of its red event and the processing of the occurred event by informing each listener through the output ports. The adapter is interposed among the source of the event and the potential listeners. Its task is to conform to the interface expected by the event source
Chapter 4. Specifying Architectures of Java Components
69
component
bean
button
Figure 4.5: Button trait in the hierarchy of component traits
trait includes bean,String button tuple of b:bean, label:String button:
Figure 4.6: Trait for a button and to deliver the red event. The main use of adapters is in demultiplexing of events. In fact any given event listener object may implement any Listener interface only once. Let us suppose now that a component such as a dialog box needs to listen to the events red by the two buttons. In this case, buttons re the same type of events to listeners which then should determine on the event reception which one of the button red. Adapters make easy the delivering of events, by taking the incoming method call from the event source, in this case one of the two button, and calling the opportune method on the target object. A button adapter interface module is showed in gure 4.10. The con guration module in gure 4.11 lists the actual instances of the components and the connectors used for the design of the system.
70
Chapter 4. Specifying Architectures of Java Components
public classButtonf uses button(ActionListeners for Listeners); private Vector listeners; private String label; public void button()f modi es self ensures self.label="button"g public void button(String s)f modi es self ensures self.label=sg public void addActionListener(ActionListener l)f requires l 2= ActionListeners modi es ActionListeners ensures ActionListeners'=ActionListeners^[flgg public void removeActionListener(ActionListener l)f requires l 2 ActionListeners modi es ActionListeners ensures ActionListeners'=ActionListeners/flgg public void processActionEvent(ActionEvent e)f requires ActionListeners 6= fg ensures 8 l:listener p:oport 2 ActionListeners let p=assoc(l) in p'=append(e, p^ )g
g
Figure 4.7: Speci cation of a button
Chapter 4. Specifying Architectures of Java Components
OK
71
doOKAction OK
Button Adapter
Cancel
Cancel
Button
Adapter
doCancelAction
Figure 4.8: Beans interaction
trait includes connector, adapter:
Queue(event,Inrole). Queue(event,Outrole) adapter tuple of conn:connector,source:inrole,dest:outrole
Figure 4.9: Trait for adapters
72
Chapter 4. Specifying Architectures of Java Components
public classButtonAdaptor f uses adapter; public void ButtonAdaptorf modi es self ensures self.dest=fg ^ self.source=fg
g
public void ButtonPushed(PushButtonEvent e)f requires self.sourcefg modi es self.source,self.dest; ensures self.source'=tail(self.source^) ^ self.dest'=append(head(self.source,self.dest^))
g
Figure 4.10: Speci cation of a ButtonAdaptor Our system is composed by an instance of a button b and a generic component d which are connected by an adapter connector a. Interaction is achieved through sharing of the events queue between the button and the adapter (and between the adapter and the other destination component). The rules in the module state that whenever a button is pushed and the corresponding event is on the input role of the adapter connector, the corresponding operation is invoked; in the same way the target component catches the forwarded call and the corresponding action can be executed.
4.7 Related Work A large amount of work has been done recently in the eld of software architecture to provide software designers with notations and tools to specify and reason
Chapter 4. Specifying Architectures of Java Components
73
button-system:con guration
component:
b:button,d:component;
connector:
a:adapter
attached:
b.comp.oport = a.source d.comp.inport = a.dest
behaves:
head(a.source)=e:PushButtonEvent behaves a.ButtonPushed(e); head(d.inport)=e:PushButtonEvent behaves d.doAction();
Figure 4.11: Con guration module for the button system about architectural designs. Two major trends can be distinguished in current approaches to formalization of software architectures: apply existing formalisms possibly enriched with new constructs for architectural descriptions or develop completely new notations guiding the architectural design.
4.7.1 Formalisms in software architecture The Chemical Abstract Machine framework has been successfully applied for the description of software architectures in [IW95]. Each cham speci cation of a system architecture consists of a syntactic part which describe how the components of a system are mapped to chemical molecules; a set of reaction rules which de ne the interactions between components; a solution which represent the initial state of the system and a set of solutions representing the intended nal states of the system. In [IWY97, IWY98] the general framework is adapted for the speci cation of components, each one modeled by a separate cham. Static
74
Chapter 4. Specifying Architectures of Java Components
properties of the system can be proved exploiting the algebraic nature of cham framework, while dynamic behaviour can be analyzed by deriving a transition system from each cham speci cation. The main drawback of such approach is that there isn't a general framework to describe the architecture, since for each system, the description must be constructed form scratch. Each cham description as well as the performed analysis are particular to the system and there are no general criteria to extend, reuse or compare speci cations for related systems. Z notation has been exploited to formalize architectural styles in [AAG95] where both a syntactic and semantic descriptions of architectural entities such as components connectors and con gurations are provided. Each style is seen as an interpretation mapping from the con guration syntax into the semantic model. The Common Algebraic Speci cation Language (CASL), developed by the Common Framework Initiative project, de nes some constructs for the modular speci cation of software systems [BST98]. An architectural speci cation in CASL consists of a set of unit declarations, showing the modules required with the speci cations for each of them, and an unit term describing the way in which these modules are to be combined. Graph grammars [LeM96, LeM98] have been used to describe architectural styles. Each graph represent an architectural instance in which nodes are the individual agents and edges de ne their interconnections. A coordinator which is expressed through graph rewrite rules, de nes the dynamic evolution of the architecture. In [MQR95], architectures are represented as theories in rst order logic and a methodology for the re nement of abstract architectures is presented.
4.7.2 Architectural Description Languages The Wright architectural language, [AG97, All97], shares many similarities with our approach to architectural descriptions, recognizing components and connectors as basic entities to be combined in con guration modules. The main dierence is its focus on patterns of interaction and the underlying formal notation,
Chapter 4. Specifying Architectures of Java Components
75
that is CSP in Wright. Relying on an abstract notation, Wright has the capability to exploit a number of known techniques and tools to perform checks on the speci cations, but the re nement to their concrete implementations may be dicult. Darwin [MDEK95, MK96] describes an architectural component in terms of the services it provides or requires during the interactions with the other components. A con guration consists of component instantiations and of the resolution of the bindings between required and provided services. A semantic model is provided by mapping the syntactical constructs to -calculus terms. Furthermore, Darwin has the ability to specify dynamically changing architectures, by de ning recon guring components. Unicon language, [S+95], provides mechanisms to construct executable con gurations starting from the descriptions of component and connectors, which are associated with an interface and an implementation. Components have a list of players which de ne the possible behavior during the interaction with the roles of the connectors to which they are attached. For well formed systems, the executable version is obtaining after a compilation phase during which a sort of parsing of the system and the resolution of the connections are performed. Rapide [L+95] uses partially ordered sets of events to specify computations and interactions between components. Analysis is based on architectural simulations which generate posets of events together with their causal histories. Aesop [GAO94] supports the speci cation and the analysis of architectural speci cations, developing architectural description environments tailored to a particular style where the concrete design of a system can be carried on. Each environment provides a set of design elements (speci c to the style), checks to ensure that the style constraints are respected by the actual con guration and a graphic interface to ACME [GMW96] focuses on the interchanging of architectural descriptions, relating computational elements described in one of the supported languages.
76
Chapter 4. Specifying Architectures of Java Components
4.7.3 Larch & Software Architecture The speci cation of software architectures is a relatively new eld of application for Larch. A similar approach was carried on by Baraona and Alexander in [BA96] where VSPEC, a Larch based interface language for VHDL, is combined with VHDL constructs to support the formal description of architectures. VHDL allows a designer to describe a digital system by producing a speci c design document which implements the desired behavior of the system in an operational style, providing also some constructs for the composition of simpler components. In [PA97] architectures are described as theories to specify the behavior of a system through a collection of axioms describing the behavior of each component. Each component is represented as an extension of a theory problem which gives the relationship between the domain and the range of a speci cation. The axioms in an architecture theory de ne component interconnections as well as component interface bindings and correctness assumptions. Such a framework allows the speci er to provide an abstract declarative description of the architecture of a system. Larch/Corba speci cation language extends the Larch approach to the Interface De nition Language used by CORBA to describe the interface that the objects provide [Siv95]. Larch/Corba speci cations integrate IDL modules with behavioral information on the services provided by each speci ed CORBA object. The lack of a formal framework to develop CORBA-compliant software limits the usefulness of the language to a sort of documentation for CORBA interfaces. A combined approach for architectural design has been presented also in [CCP97b], where both Z [Spi92] and Larch [GH93] notations are used for software architecture speci cations, within the Clepsydra methodology [CCP97a].
Chapter 5
A Reduction Semantics for Java 5.1 Introduction Since the rst release of Java and the Hot-Java browser, a number of aws have been discovered compromising their security. These aws are due to implementation errors, to misleading interpretations of the Java speci cation or even to undervalued issues and weaknesses introduced in the design of both the Java language and the byte-code. A taxonomy of bugs and errors in Java has been presented in [DFW96]. Even if many of the detected aws have been patched in the successive releases of the language, new bugs are found while the use of Java spreads among software developers. Saraswat showed in [Sar97], how simple and apparently harmless programs can crash Java interpreters, exploiting a bug in the class loading policy used by current Java implementations. The Sun site (http://java.sun.com) maintains a continuously updated list of the previous, currently known and still unresolved errors signaled by Java users. (Visitors of the site can even vote for the bug they would like to be rst resolved in the next release of the Java Development Kit!). A source of errors must be found in the lack of any formal methodology both in the design and implementation of the Java framework. The reference manuals, which are the only ocial description of the Java language, are ambiguous or
78
Chapter 5. A Reduction Semantics for Java
inconsistent, if submitted to a rigorous and detailed formal analysis [Ber97]. This is not so singular, since Java incorporates many novel features (class loading, dynamic linking, applets, etc.) which are not easy to understand and are indeed current subject of research in object oriented theory. Without a strong theoretical foundation, claims about security of the Java system cannot be de nitive and can be continuously revised, as long as new issues or bugs are found. In fact, despite a large amount of work [DE97a, DE97b, SA97, Sar97, Sym97], debate on safety of Java type system continues both on newsgroups (see
[email protected] mailing list or http://www.cs.indiana./edu/hyplan/pierce/common/prof/Types.html) and related conferences.
5.1.1 Our approach We think that a rst step for the analysis of Java programs is the de nition of its formal semantics. It is well known that formal semantics dispense with ambiguities in the informal description or misinterpretations of the reader. Our aim is to model, in a comprehensible way, the basic mechanisms which underlie Java programs execution. To this purpose we commit to a simple technique for formalizing the semantics, the reduction style. This technique has been pro tably used for de ning the semantics both of functional languages (see Barendregt's book [Bar85], for instance) and concurrent processes [Bou97]. In particular, in concurrency theory, reduction semantics has been re ned into chemical semantics [BB90], where features as parallelism and distribution are modelled in a simple way. In this chapter we focus on the object oriented kernel of Java. We de ne inheritance, subtyping, overriding and overloading, the dynamic class loading policy, object creation and method invocations. We voluntarily restrict here to the object oriented kernel because Java is already innovative in this subset. The detailed formalization of the interrelationships between the object oriented features is necessary to achieve a complete comprehension of Java programming environment, nding out its potential weaknesses.
Chapter 5. A Reduction Semantics for Java
79
The chapter is organized as follows. In section 5.2 we present the syntax of the subset of Java. We leave out of our treatment visibility rules, interfaces, packages, arrays. All these features as well as exceptions or thread management constructs can be handled by extending the grammar and adding new semantics rules in an almost standard way. Basic notations, such as those to manage memories and environments are collected in section 5.3. In section 5.4 we de ne the semantics of standard features of object oriented programming, such as object creation and method invocation. The class loading process is discussed in detail in section 5.5, were we describe meticulously every method of the class Classloader. An overview of the results in the literature and a comparison with them can be found in section 5.8.
5.2 The object oriented kernel of Java The basic operations we allow in the restricted language are: object instance creation, method invocation and eld selection and updating. The following is the syntax for CoreJava programs: Stm ::= " j return j return (Exp) j Com ; Stm j Type Id ; Stm j fStmg; Stm Com ::=
() j QId (Exp) j QId = Exp
new Id
Exp ::= QId j Com j Val QId ::= Id j Id:Id j
[:Id] j
this
[:Id]
super
Id ::= string
Here is a smooth informal description of the above instructions, ordered by syntactic categories. A detailed description may be found in the Sun's Java Language Speci cation [GJS96].
80
Chapter 5. A Reduction Semantics for Java
The category Stm. The sequence of execution of a Java program is controlled
by statements which are executed for their eect and do not have values. Statements can be collected in blocks represented by braces. A block is a sequence of statements and variables declarations which are executed in order. The empty statement does nothing; then body of methods or blocks can be empty. A return statement returns the control to the caller of a method or a constructor. If the return statement has no expression, then the invoked method has to be declared not to return any value (i.e., its return type is void). If an expression is provided, then the value of the expression becomes the value of the method invocation, provided that their types are compatible as speci ed in Section 5.3 Any variable declaration Type Id introduces one (local) variable name Id, whose type is Type. The scope of a local variable declared in a block is the rest of the block. Redeclaration or hiding of local variables is not permitted. If the local variable has the same name as a eld, the outer declaration is hidden in the scope of the local variable and can be accessed by using a quali ed name. To distinguish between variable access and eld access we assume that elds are always referred through their quali ed names. Certain kind of expressions, such as assignment, class instance creation and method invocation may be used as statements if followed by a semicolon; in this case, once executed, the returned value if any, is discarded.
The category Com. The operation new C is used to create new objects of class
. This statement, besides allocating space for the object components, invokes the constructor of the named class. A method invocation expression with form m(e) or a.m(e), is used to invoke an instance method (we do not deal with class methods, i.e., methods declared static which are shared by all the instances of a class). Finally assignment expressions are used to change values of variables or elds C
Chapter 5. A Reduction Semantics for Java
81
provided that the type of the variable and the value of the expression on the right hand are compatible (see Section 5.3).
The category Exp. The simplest kind of expressions are literals in Val which
denote xed values. Identi ers, i.e., valid sequences of characters, are used to name the entities in a Java program, denoting variables or members or types. Simple names are simple identi er, quali ed names consist of sequence of two identi ers separated by a dot. Expressions denoting variables are evaluated by substituting the value of the variable according to the current environment. Fields are accessed through quali ed identi ers. The keyword this denotes a reference to the object for which the instance method was invoked or to the object being constructed; super acts as a reference to the current object as instance of its superclass. They can be used only in the body of an instance method or constructor.
5.2.1 Class declarations A Java program is structured as a sequence of class declarations, which are templates for objects. Java supports single inheritance, i.e., a new class can extend exactly one superclass and class Object is at the root of the total class hierarchy. Objects created The following is the grammar for Java programs:
82
Chapter 5. A Reduction Semantics for Java
Dec ::= "
j j
Body ::= "
class Id
fBodyg Dec
class Id extends Id
fBodyg Dec
j MType Id (Flist) fStmg Body j Type Id ; Body Flist ::= " j (Type Id) MType ::= void j Type Type ::= Primitive-Type j Reference-Type
The category Dec. This category de nes classes in the usual way. The
clause de nes the direct superclass of the class being constructed; whenever the extends clause is missing, the class is assumed to implicitly extend the class Object. extends
The category Body. The attributes of a class may be of two kinds: elds or
methods. A eld declarator introduces variables associated with the class and its objects, while a method contains executable code to change object's state. Each method is distinguished by its name and by the number and the type of its parameters which are speci ed in the method declaration. For each method the result type must also be speci ed; a void method is a method which does not return any value.
The category Type. Each eld has a type which de nes the values it takes.
Primitive types are the Java built-in data types such as int or float; reference types are created after a class declaration and the values are references to objects of that class.
Chapter 5. A Reduction Semantics for Java
(class) class C fB g (subclass) class C extends C 0 fB g (seqdec) D D0 (field) type I ; B (method) mtype I (type x) fStmg B
! ! ! ! !
83
C : (Object; B ) C : (C 0; B ) D; D0 fI : nulltype g [ B f(I; x; nulltype ; nullmtype ) : Stmg [ B
Table 5.1: Shape of classes
5.2.2 Semantics of declarations Table 5.1 de nes the semantics of declarations. Every class declaration is represented by a tuple, where the name of the class, its direct superclass and its body are stored. A variable declared in a eld is identi ed by its name I and is associated with its value. For simplicity, we disallow contemporary declaration and initialization of eld variables. Therefore the initial value for a variable will be the null value for the declared type. The eect of a declaration clause is to bind the identi er to values of the declared type. For declarations involving reference types, the object creation is delayed until an explicit call to the constructor of the class is made. Finally each method declaration is stored as a tuple composed by its name, number and type of identi ers and of return value; the tuple so obtained is associated with its body. The rules in table 5.1 can be extended to deal with an arbitrary number of parameters. Example 5.2.1 We examine a simple program in Java which de nes points and
re nes them by adding colors. Class Point has two elds de ning the coordinates of the point and a move method to update the point location. Class Pixel re nes the previous class by adding a new eld holding the color associated with the point and overriding the move method to take into account the color eld. class Point
f
int x;
84
Chapter 5. A Reduction Semantics for Java int y; void move (int dx, int dy)
f
this.x=dx; this.y=dy;
g
return
g
class Pixel extends Point
f
int color; void move (int dx, int dy, int dc)
f
super.move(dx, dy); this.color=dc;
g
return
g
By the semantic rules we get:
f Point:
( Object, f x: nullint , y: nullint , (move, dx, nullint , dy, nullint , nullvoid ): f this.x=dx;
Pixel:
g
g
this.y=dy; return
( Point, f color: nullint , (move, dx, nullint , dy, nullint , dc, nullint , nullvoid ): f g
g
g
Chapter 5. A Reduction Semantics for Java
85
5.3 Basic notation We devote this section to introduce few de nitions of the basic entities we need in the rest of the chapter. Java is a strongly typed language, that is every variable and every expression has a type which limits the values that a variable can hold or an expression can produce as well as the operations on those values. We denote with Val the set of primitive values or literals. For the sake of simplicity we restrict Val to contain nite numeric values (integer or oating-point numbers as represented in Java) and boolean values (true or false). Let Ref be the set of reference values, namely pointers to objects. Reference values are stored as tuples (; C; C 0; L), where the function returns the value of the associated elds, the declared type C, the runtime type C 0 of the object and the loader L used to get those classes. Indeed Java, as every object-oriented language, distinguishes between compile and runtime types in order to retrieve method codes. Namely, Ref ((QId *f N ) Id Id Id)
where *f denotes a partial function and N are natural numbers. Therefore the shape of a reference value will be (; C; C 0; L). We also denote the domain of a function f with dom(f ). For a reference value v we use the notation v:fun, v:dtype, v:rtype and v:loader to access the referenced object, its declared and runtime type and its loader, respectively. We also de ne Let < C:x > :
if x 2 BC
Fret(C 0; x) otherwise
The semantics of statements and expressions is de ned in Table 5.4 and 5.5, respectively. The rst rules of Table 5.4 deals with assignment which is modeled by suitable updating of the memory. As previously explained, if an evaluation of an expression is needed, then the application of the rule is delayed till the return of the calculated value. In the rst rule dealing with eld updating, we use the auxiliary function Fret for retrieving the eld, starting from the declared class of the object. Assignment for local variables, is simply resolved by updating the location associated to the named identi er by the current environment ?. Note that, for primitive types, a type checking is performed, since memory updating for values with dierent types is not de ned.
96
Chapter 5. A Reduction Semantics for Java
C ; ?;
M ` [(; C; C 0; L):x = k; S ] ! C ; ?; M[(Fret(C; x)) 7! k] ` [;; S ]
C ; ?;
M ` [ x = k; S ] ! C ; ?; M[?(x) 7! k] ` [ ;; S ]
C ; ?;
M ` [;; :x = e; S ] ! C ; ? fg; M ` [;; e][:x = ; S ]
where = (; C; C 0; L) C ; ?;
M ` [ ;; x = e ; S ] ! C ; ? fg; M ` [ ;; e ] [ x = ; S ]
C ; ?;
M ` [ x = (; C; C 0; L); S ] ! C ; ?; M[?(x) 7! o] ` [ ;; S ]
where - C