an introduction to distributed programming in rex - CiteSeerX

1 downloads 2515 Views 61KB Size Report
Configuration Programming is an object-based approach to distributed ... is essential for all phases in the software development process, from system ...
ESPRIT CONFERENCE 91 Project Nr. 2080

AN INTRODUCTION TO DISTRIBUTED PROGRAMMING IN REX Jeff KRAMER, Jeff MAGEE, Morris SLOMAN, Naranker DULAY, SC. CHEUNG, Stephen CRANE, and Kevin TWIDLE Department of Computing, Imperial College of Science, Technology and Medicine, 180 Queen's Gate, London SW7 2BZ, UK. ([email protected]) ABSTRACT Configuration Programming is an object-based approach to distributed programming. The main principle underlying this approach is that programs should be designed, constructed and modified as a structural configuration of interconnected component instances. Program structure is described by a separate explicit configuration language, while the components themselves may be programmed in a range of heterogeneous programming languages. This approach is central to the ESPRIT II project, REX, on reconfigurable and extensible parallel and distributed systems. This paper provides an overview of the main concepts underlying REX, illustrating their use in the Darwin configuration language for describing overall system structure and dynamic configuration. The approach is justified and briefly compared to object-oriented programming. 1. INTRODUCTION The REX25 project, “Reconfigurable and Extensible Parallel and Distributed Systems”, aims to develop an integrated methodology and associated support tools for all phases in the development and management of parallel and distributed systems. Ten European partners from industry and university research groups are involved 1 . The project started in May 1989 and is to run for a total of 5 years. Two large demonstrators in the telecommunications and Computer Integrated Manufacturing (CIM) areas act as a focus for the work and as a means for demonstrating the techniques and tools developed. The key feature of the REX approach is its emphasis on configuration structure. Practical experience in software engineering has taught us that complex systems can be built and managed provided we adhere to some sound principles. Software modularity is essential, and permits the use of composition to form a system. In particular, distributed systems are conveniently described, constructed and managed in terms of their software structure. Descriptions of the constituent software components and their interconnection patterns provide a clear and concise level at which to specify and design systems, and can be used directly by construction tools to generate the system itself. In many cases - particularly embedded applications - it is the structure of the application itself which is used to dictate the structure of 1

The REX partners are Imperial College and PRG Oxford in the UK; GMD Karlsruhe, Siemens, Stollman, Karlsruhe University, T.U.Berlin and 2i in Germany, Intracom (and Intrasoft) in Greece, and Tecsi in France. Dirk Dettmann of Stollman is the Project Manager, and Jeff Kramer of Imperial College is the Technical Director.

the resultant system. This approach is referred to as "configuration programming" 11,13. Extension and evolution of the system can be achieved by making changes to the system configuration 10. The premise of the approach is that a separate, explicit structural (configuration) description is essential for all phases in the software development process, from system specification as a configuration of component specifications, to evolution as changes to a system configuration. Our development process is essentially "constructive" 12, emphasising the satisfaction of system requirements by composition of components. The formal view of this constructive approach is that of system verification by showing satisfaction of the system specification as a composition of component specifications. This approach thus emphasises composition as a basic operation of configuration, with the need to support composition of actual system components and specifications. Hence, system configuration (structure) is recognised as the unifying framework in REX. As stated in the project synopsis, “...the notion of the system as a configuration of modular software and hardware components will be used as the framework on which to hang the research work on system specification, analysis, construction and modification” 25. We believe that this emphasis on configuration structure leads to clear and flexible designs, and results in distributed object-based systems which are comprehensible and maintainable. The structural view is particularly useful in facilitating change and evolution in the form of dynamic configuration. Furthermore, REX components may be programmed in a range of heterogeneous programming languages. Overview of the Rex Software Architecture Interface described by REX ISL

Rex Component

Implemented in range of Programming Languages ( C, Ada, Pascal etc) + REX Communication primitives

Figure 1 - Program Components Central to the REX project is the view of distributed and parallel systems as interconnected sets of component instances. Program components are objects2 which encapsulate state and have well defined interfaces specified by an Interface Specification Language (ISL). The functionality of a program component may be implemented in a range of programming languages; however, interaction with other components utilises a common set of communication primitives supplied by the REX runtime system (Figure 1). These communication primitives provide for both synchronous (bidirectional) and asynchronous (unidirectional) communication. Components in REX are types (c.f. classes) from which more 2

Wegner 27 makes a distinction between object based, class based and object oriented languages. Object based languages support encapsulation in the form of objects, class based extends this to include classes and object oriented further extends this to include inheritance. Strictly speaking, our language can be classified as class based.

than one component instances can be created. Component instances execute in parallel. The sets of instances which exist in a system together with their interconnections (Figure 2) are specified in a separate configuration language - Darwin.

Figure 2 - Systems In addition to describing overall system structure, Darwin permits systems to be composed hierarchically by allowing the specification of composite components which are configurations of either simple program components or other composite components. The interface to a composite component is specified by the ISL in an identical way to program components (Figure 3). In this way, program components may be replaced by composite components and vice-versa without affecting the rest of the system structure. Finally, Darwin is also used as the language in which to express system extension and modification by structural changes.

Figure 3 - Composite Component Section 2 of the paper illustrates the utility and versatility of the configuration oriented approach using a simple telephone exchange as an example. Section 3 discusses the approach, providing a brief comparison with object-oriented programming. Finally, section 4 concludes by summarising the principles of the approach and giving the current status of the work. 2. CONFIGURATION PROGRAMMING IN REX The main concepts of configuration programming, namely those of explicit structure and hierarchic composition, are illustrated by examples from the REX environment for the development of distributed programs. We concentrate on the configuration facilities provided by Darwin, the REX configuration language. Darwin includes facilities for hierarchic definition of composite components, for parameterisation of components, for multiple instantiation of both components and interface interaction points, for dynamic binding and instance creation, for conditional configurations with evaluation of guards at component instantiation, and even for recursive definition of components. This work owes much to earlier experience using the Conic configuration language 10,18. Telephone Exchange Example Figure 4 illustrates a simple telephone system consisting of a number of telephones

interconnected by an exchange. To illustrate the configuration programming approach to developing parallel and distributed systems, we will develop a functional simulation of the telephone exchange using the REX programming system.

Exchange

Figure 4 - Simple Telephone system 2.1

Hierarchic component composition

In REX component classes are defined by component types which can be instantiated to form components. Figure 5 depicts, in both graphical and textual forms, an initial decomposition of the exchange into instances of two component types - lineunits lu and a switch. Each lineunit handles a subscriber and incorporates the call processing functions to decode control information from incoming signals, return dialling tone, collect digits, and send ring signals. In response to control commands, the switch sets up the simulated speech and signalling paths between the lineunits representing the incoming and outgoing sides of a telephone call.

exchange lu[0] line[0]

Sline line

switch Sline[o]

control lu[1] line[1]

Sline line

Sline[1]

•••

control

lu[n-1] line[n-1]

Sline line control

Sline[n-1] control

component exchange(n:int) = { entry line:[n] lineT; // array of ports use exchdefs:lineT; // port types lineunit; // component types switch; inst switch(n); // switch names both the instance and the type forall i:0..n-1 { inst lu[i]:lineunit(i); bind line[i] -- lu[i].line; // bind to interface lu[i].Sline -- switch.Sline[i]; // internal bindings lu[i].control -- switch.control; } }

Figure 5 - Exchange Configuration The program textual description is expressed in the REX configuration language Darwin. The description specifies which component types are used to construct a composite component (use), which component instances of these types are created by the composite component (inst) and how the ports of these instances are interconnected (bind). Component types can have formal parameters which are resolved when the component is instantiated. The exchange component is parameterised by n the number of lines it supports. This parameter is used to dimension the array of interaction points line and also the array of lineunit instances lu. 2.2

Interface Specification

In general, the interface to a component is specified in ISL by typed ports. In this case it is the array of entry ports line of type lineT. This type is imported from a file of port type definitions used by the telephone system (listed below):

types exchdefs = { lineT = {in: port char invert out: port char }; controlT = port int, int,int -> int; Nmax = 32; BUSY = 1; OK =2; }

// asynchronous // asynchronous // synchronous

LineT is defined as a port set which consists of two ports of type char. These ports have opposite invocation directions indicated by the keyword invert which denotes that if in is an entry port out will be an exit port and vice-versa. Consequently the interface declaration of Figure 5 (entry line:[n]lineT) declares an array of port sets in which each set consists of an entry port in and an exit port out. A component accepts invocations from entry ports and invokes the services of other connected components via exit ports. In the above, in and out support asynchronous unidirectional invocations ie. the information flow is from the exit port to the entry port and the caller does not wait for a response; whereas controlT supports conventional synchronous operation invocation ie. information flow is in both directions and the caller waits for a response. 2.3 Dynamic Binding The component which implements the exchange switching function is depicted in Figure 6. The switch component includes an example of dynamic binding (and unbinding). In response to control commands, the controller component invokes configuration changes to connect and disconnect paths between the lineunits indicated by the change parameters. The interface to the lineunits is represented by the port array Sline. Changes can be considered to be reconfiguration “methods”. They are invoked (and bound to) components in an identical way to programmed methods. In addition to bindings, changes may specify the creation of new component instances and the removal of old instances. in out

switch Sline[0]

in out Sline[1] change

in out

connect

change disconnect

Sline[n-1] Controller control control

component switch(n:int) = { entry Sline:[n] lineT; control:controlT; use exchdefs:lineT,controlT; controller; inst

connect disconnect

controller; // controller names both the instance and the type change connect (incoming: int; outgoing : int) = { bind Sline [incoming].out -- Sline [outgoing].in; bind Sline [incoming].in -- Sline [outgoing].out } change disconnect (incoming, outgoing : int) = { unbind Sline [incoming].out -- Sline [outgoing].in; unbind Sline [incoming].in -- Sline [outgoing].out } bind controller.control -- control; controller.connect -- connect; controller.disconnect -- disconnect; }

Figure 6 - Switch Component 2.4 Programmed components Figure 7 shows the program for the programmed component controller. Each program component instance executes with its own thread of control. It is an active component or process. The programming language is C to which has been added a component header part, remote invocation (call ) and invocation handler (accept ) statements. For example, in figure 7, control commands are handled by accepting invocations from the entry port control. This is a synchronous invocation. The calling component waits for the invocation to complete. Completion occurs when the called component executes a reply. A component may selectively wait on a set of entry ports using a select construct similar to that provided in Ada. More details on the invocation primitives can be found in the paper by Magee et al 19. The augmented C is compiled by the REX toolkit into standard C. In addition the toolkit supports heterogeneity and allows for components to be programmed in other languages such as Modula 2. component controller = { use exchdefs; // import all definitions from exchdefs entry control:controlT; exit connect: port int,int; disconnect: port int,int; } %%c

// indicates implementation follows in C

int C[Nmax]; // records connections main(){ int incoming,outgoing,operation; for ( ; ; ) { accept control (operation,incoming,outgoing); switch (operation) { case CONNECT: if ( ! C[incoming] && ! C[outgoing]) { call connect(incoming,outgoing); C[incoming]=outgoing; C[outgoing]=incoming; reply control(OK);

} else reply control (BUSY); break; case DISCONNECT: call disconnect(incoming,outgoing); C[incoming]=C[outgoing]=0; reply control(OK); break; } }

Figure 7 - Controller Component 2.5

Distribution

So far we have not considered distribution of the example. Distribution is achieved by annotating a configuration description with processor allocations using the @ construct. For example, figure 8 shows the exchange component modified to allocate each lineunit to a different processor. The processor(i) part of the @ clause is a function which maps the virtual processor numbers to physical processor names or addresses. By default, component instances are created on the same processor as their parent group. Hence, the switch component instance will be created at the same processor where exchange is instantiated. component exchange(n:int) = { entry line:[n] lineT; use exchdefs:lineT; lineunit; switch; inst switch (n); forall i:0..n-1 { inst lu[i]:lineunit(i) @ processor(i); bind line[i] -- lu[i].line; lu[i].Sline -- switch.Sline[i]; lu[i].control -- switch.control; } }

Figure 8 - Exchange Configuration 2.6

Conditional & Recursive Configurations

The exchange example includes examples of component instance arrays, port arrays and dynamic binding. The following example of a binary tree of component instances demonstrates the features in Darwin to support conditional and recursive configurations (Figure 9). The configuration declarations within the curly brackets following a when clause are only evaluated if the when condition (in this case depth>1) is true. RightTree and LeftTree are both instances of the enclosing type BinTree giving the recursive structure definition. Note that in BinTree the invocation direction and datatype of the port parent has not been specified. These can be inferred by the configuration compiler from the component type node. This ability to

delay the direction and type specification of ports supports top down design in that detail can be added as the design is decomposed into sub-components. parent

BinTree parent root left

right

parent

parent

parent root left

parent root left

right

LeftTree

right

RightTree

component BinTree(depth:int) = { port parent; use node; inst root : node; when depth>1 { inst LeftTree :BinTree(depth-1); RightTree:BinTree(depth-1); bind root.left -- LeftTree.parent; root.right -- RightTree.parent; } bind root.parent -- parent; }

Figure 9 - Recursive Binary Tree Component 3. DISCUSSION AND JUSTIFICATION In this section we discuss and justify the concepts in the REX approach, particularly in relation to Object Oriented Programming (OOP). OOP combines a number of sound and useful concepts in a form which has captured the popular imagination 28. Encapsulation permits the association of state and behaviour to form an object. Classes serve as templates from which object instances are created and so permit the reuse of a single behaviour specification for the set of all object instances created from that class. Inheritance provides a mechanism for the reuse of the behaviour of one class in the definition of a new class. It establishes a class hierarchy which represents a generalisation / specialisation relationship between classes. All these are very appealing notions. However, there are some weaknesses in OOP and its use for distributed programming.

3.1 Explicit Configuration Structure We argue that the weaknesses of OOP emanate from the lack of an explicit description of program structure. We have shown that a separate and explicit description of program structure facilitates program description, construction and modification, and believe that it complements the object oriented concepts yet is missing from most other OO approaches. For instance, Object Oriented Design (OOD) methods concentrate on the definition of classes in an inheritance hierarchy. This hierarchy defines the relation between classes, but ignores the actual structure of the required program. Actual program structure is poorly expressed, being embedded in the object code. Structure needs to be defined in terms of object instances. Explicit program structure, in terms of object instances and the interconnections or bindings between them, is a natural outcome of traditional design techniques such as the system structure diagram of JSD 6, Data Flow Diagrams and Structure Charts of SASD 22. This resulting design structure of object instances can be used to determine the classes required to perform the application processing 12, and can then be organised into an inheritance hierarchy to try to maximise software reuse. To some extent, this lack of an explicit structural description in OOD is excused by the use of dynamic object creation and dynamic binding between objects. However, it is very difficult to determine the current overall structure of a program as it is embedded in the object code as parameters, instructions for instances to be created and references to objects to which bindings are required. We have shown that even such dynamic programs can benefit by making the possible object instance structures more explicit. In addition, structural descriptions provide a clear and useful reference abstraction for the personnel involved in the distributed development process, including program construction, evolution (modification) and software management.

m1 local state Interface

m2 m3

Behaviour:

Implementations of methods m1,m2,m3

state changes in response to method invocation

Figure 10. - An Object in OOP 3.2 Interfaces for Context Independence Modularisation is a necessary facility not only for distribution, but also for sound software engineering. One of its recommended principles is that the interface to a module should explicitly define all the means of affecting its behaviour and state. Let us examine and assess object interfaces in this light. Objects interact by invoking methods. An object interface is usually described by those methods which it offers (figure 10). However, its use of the methods of other objects is not descibed explicitly at the object interface but embedded internally in the object code. This is analogous to the publication of offered service interfaces in distributed systems but the hiding of service requirements. We believe that both the “services” provided and required are necessary for the description of object behaviour and ought to be explicitly defined at the object interface. The interface can thus clearly and explicitly identify the methods offered and used,

the types of data associated with each, and even the form of interaction (synchronous or asynchronous invocation). Invocation of methods represented by xp1,xp2

ep1

xp1 local state

ep2 ep3

xp2 Implementations of methods represented by entryports ep1,ep2.ep3

Figure 11 - An Object with explicit interfaces This symmetry in interface definition can be extended to object naming. In the same way that, from the point of view of the invoked object, an invocation is from an anonymous (unnamed) object, so calls on other objects can be anonymous by making them indirectly via a port. Object code need never refer directly to other objects by reference, but rather indirectly via its port interface. In this way, objects achieve context independence. This facilitates the use and reuse of an object in different environments. Object port binding can then be performed separately. In practice context independence can be achieved by defining an object interface in terms of: i) the set of typed entry ports representing the methods the object provides, ii) the set of typed exit ports representing the methods required from other objects (Figure 11). 3.3 Concurrency and Distribution What of concurrency and distribution? For instance, at what granularity level should concurrency be provided? Should objects become active entities like processes, or should there rather be the ability to create threads of execution within objects? The latter thread model provides a finer grain of concurrency, but requires the use of additional internal concurrency control primitives (such as semaphores) for synchronisation and to control access to shared data 21,26. Use of such synchronisation primitives is generally difficult and error-prone. Although some improvement has been made by permitting separate expression of this synchronisation in systems such as Guide 3, they can still require highly complex expressions. In order to make the concurrency control clearer, the grain of active concurrency can be made coarser and restricted to coincide with an object. This leads us to a more uniform form of concurrency which is clear and well suited to distribution. As illustrated, our approach is the use of sequential active objects (cf. process components) which communicate directly with one another by remote method invocation. A distributed program then consists of a number of distributed communicating objects, which can handle one invocation at a time. This has sacrificed the fine-grain concurrency of the concurrent threads approach, and adopted the object as the grain of concurrency and distribution. In so doing, the need for additional synchronisation primitives within an object are obviated and instead all that is necessary is the ability for an object to wait on a selection of possible invocations/messages. Such active objects are particularly attractive if the conventional synchronous method invocation is

extended to include asynchronous invocation. 3.4 Inheritance and Composition Inheritance in Object Oriented Programming languages permits objects to share both behaviour and data with their parent superclasses. However, while it is easy to see the utility of this mechanism in constructing complex sequential object behaviour, it is less simple in relation to parallel and distributed systems as object encapsulation can be violated. For instance, a subclass may refer to variables or local private operations in its superclass, or even to superclasses further up the inheritance hierarchy. Such use of shared class variables and procedures cannot be efficiently supported in distributed systems. Wegner 27 has gone so far as to state that “...distribution is inconsistent with inheritance” . On the other hand, composition seems to offer a viable, sensible and efficient alternative to inheritance. Composition is a technique for constructing systems, whereas its inverse, decomposition is a means of designing systems. Composition provides a powerful means of abstraction in that it permits a collection of components to be treated as a single component (figure 5). Composition supports reuse in that it permits a new class to be defined in terms of instances of existing classes. Raj and Levy 24 also prefer the use of composition; however, in our case, the definition of a composite class uses a separate structural configuration language. 3.4 Summary The REX approach illustrated in the previous sections is based on the use of active objects (termed components), both synchronous and asynchronous method invocation and explicit interfaces and bindings. An explicit configuration language is used to define program structure as a set of components and their bindings. This configuration language, Darwin, is separate from those used for programming components as context-independent types (like classes) with well-defined interfaces. The configuration language includes facilities for hierarchic definition of composite components, for parameterisation of components, for replication of both component instances and interface interaction points, for conditional configurations with evaluation of guards at component instantiation, and even for recursive definition of components. In addition, the approach supports dynamic configuration, expressible at the configuration level as programmed changes to the configuration of component instances and/or their bindings. In addition, evolutionary changes can be similarly expressed but applied interactively.

4. Conclusions We believe that the combination of OOP concepts with explicit structural description has much to offer in programming distributed systems. Others have also recognised the importance of the structural configuration view in a distributed environment 1,5,8,10,15,16,17,20,23. The REX software architecture has been primarily influenced by the basic principles of configuration programming outlined in 10,13. In the following we briefly relate the approach to these principles. 1. The configuration language used for structural description should be separate from the programming language used for basic component programming. REX goes further than this by the use of an Interface Specification language which makes the configuration language Darwin completely independent of the language used to program component behaviour. Darwin may thus be used to construct systems which consist of heterogeneously programmed components.

2. Components should be defined as context independent types with well defined interfaces. The REX ISL specifies both the ports through which remote services are accessed as well as the ports which represent services that a component provides. A component thus makes no direct references to non-local entities. It can thus be used in many different contexts by binding its ports. 3. Using the configuration language, complex components should be definable as a composition of instances of component types. As illustrated in section 2. Darwin provides exactly this. Further, no distinction is made between complex components and basic program components in terms of their use and instantiation. 4. Change should be expressed at the configuration level, as changes of the component instances and/or their connection. Although REX allows program components to instigate changes to the structure of a system, the changes themselves can only be described in Darwin in terms of instances and bindings. The REX work is heavily based on Conic, with which we have had extensive experience for a number of years. This has provided us with convincing evidence of the utility of the configuration approach for distrbuted program design 12, construction 18, evolution 14 and management using graphic tools such as ConicDraw 11. However, a number of limitations to Conic and its implementation have also been recognised. It provided support for post hoc evolutionary change but no linguistic support for dynamic programmed change, where the configuration changes are embedded in the configuration description (as illustrated in the exchange switch). Component interfaces in Conic are simpler and do not support port sets and the associated binding rules. Finally, there is no integrated support for components written in different programming languages. These limitations are being addressed in REX and its configuration language, Darwin. The current status of the work is that Darwin has been implemented and the communication primitives have been embedded in components written in C or C++. Colleagues in the REX project are embedding the primitives in other languages such as Modula 2. Management tools are also being developed to monitor and control system configuration. RexDraw (cf. ConicDraw) will provide a graphic facility while an OSL (Object Selection Language) 7 will provide for the description of generic configuration management. In addition, open systems connection is to be provided by the ability to publish specified interfaces either as services offered or required (figure 12).

Distributed Rex Programs Management Tools RexDraw

OSL Interpreter

External Namespace/ Binding Environment

Non- Rex services

Figure 12 - Distributed Systems Management and Open Systems As mentioned, the REX project is providing tools to support all phases in the development of reconfigurable and extensible parallel and distributed systems: specification, design, construction, analysis and management. Such tools are being built to exploit the use of a separate structural description of a system. For instance, a prototype design tool, RexDesigner, has been constructed to support the Constructive Design Approach 12, a method which utilises the structural view during the design process. The REX project offers multiple component programming languages to suit the programming task at hand. Similarly, to provide support for diverse application domains, REX supports multiple specification and analysis techniques and the integration of multiple methods. Specification and method integration is provided through the use of a novel approach, called ViewPoints 4, which supports specification and method partitioning and interaction through explicit transformations analogous to those used in software configurations. Furthermore, a REX Engineering Environment 9 is intended to provide a general facility for integrating information produced during any of the phases of software development and maintenance. It provides an attributed file system combined with language facilities for enveloping and controlling the invocation of slave CASE tools and compilers. A generalised attribute mechanism is provided to allow specification and design tools to attach information to configuration descriptions. These attributes, which can include timing and behaviour constraints, can be checked during system construction with the aim of ensuring compatibility between components when their interfaces are bound. Acknowledgements: Acknowledgement is made to our colleagues at Imperial College (Anthony Finkelstein, Keng Ng) and also to our partners in the REX project for their contribution to the work described in this paper. We gratefully acknowledge the SERC under grant GE/F/04605 and the CEC in the REX Project (2080) for their financial support.

ESPRIT PROJECT 2080

Reconfigurable and Extensible Parallel and Distributed Systems REFERENCES (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19)

BARBACCI,M.R.,WEINSTOCK,C.B. and WING,J.M. (1988). "Programming at the Processor - Memory - Switch Level", Proc. of 10th IEEE Int. Conf. on Software Engineering, Singapore. BLACK,A., HUTCHISON,N.,JUL,E., LEVY,H., and CARTER,L. (1987). “Distribution and abstract types in Emerald”, IEEE Trans. on Software Eng. SE-13(1), 65-76. DECOUCHANT,D.,LE DOT,P., REVEILL,M., ROISIN,C., and ROUSSET DE PINA,X. (1981). “ A Synchronisation Mechanism for an Object Oriented Distributed System”, Bull-IMAG, Rapport Technique 9-9. FINKELSTEIN,A., KRAMER,J. and GOEDICKE,M. (1990). “ViewPoint Oriented Software Development”, Proc. of Third Int. Workshop on Software Engineering and its Applications, Toulouse. GOGUEN,J.A. (1986). "Reusing and Interconnecting Software Components", IEEE Computer, (Designing for Adaptability), Vol. 19, 2. JACKSON,M.A. (1983). "System Development", Prentice Hall. JIAWANG, W. and ENDLER, M. (1991) “A Configuration Model for Dynamically Reconfigurable Distributed Systems”. Proc. of 24th HICSS Conference, Hawaii, 265279. KAPLAN,S. and KAISER,G. (1988). “Garp: Graph Abstractions for Concurrent Programming”, ESOP '88, Nancy, France, Springer-Verlag, 191-205. KOCH,W., NAGEL,K. and OBST,W. (1991). “Guiding System Evolution by Task Engineering Tools”, Proceedings of the 5th Conference on Software Engineering Environments (SEE’91), Aberystwyth, Wales. KRAMER,J., and MAGEE,J.(1985). "Dynamic Configuration for Distributed Systems", IEEE Transactions on Software Engineering, SE-11 (4), 424-436. KRAMER,J., MAGEE,J., and NG,K. (1989). "Graphical Configuration Programming", IEEE Computer, 22(10), 53-65. KRAMER,J., MAGEE,J., and FINKELSTEIN,A. (1990). “A Constructive Approach to the Design of Distributed Systems”, Proc. of 10th Int. Conf. on Distributed Computing Systems, Paris, 580-587. KRAMER,J. (1990) “Configuration Programming - A Framework for the Development of Distributable Systems”, Proc. of IEEE COMPEURO’90, Tel-Aviv, Israel, May 90, pp 374-384. KRAMER,J., and MAGEE,J., (1990). "The Evolving Philosophers Problem: Dynamic Change Management", IEEE Transactions on Software Engineering, SE-16 (11), 1293-1306. LEBLANC,R.J. and MACCABE,A.B. (1982). “The Design of a Programming Language based on a Connectivity Network”, Proc. 3rd Int. Conf. On Distributed Computing Systems. LEBLANC,T. and FRIEDBERG,S.. (1985). "HPC: A model of structure and change in distributed systems". IEEE Trans. on Computers, Vol. C-34, 12. LEE,I., PRYWES,N. and SZYMANSKI,B. (1986). “Partitioning of Massive/Real-Time Programs for Parallel Processing”, in Advances in Computers, ed. M.C. Yovits, Vol.25, Academic Press. MAGEE,J., KRAMER,J., and SLOMAN,M. (1989). "Constructing Distributed Systems in Conic" IEEE Transactions on Software Engineering, SE-15 (6). MAGEE,J., KRAMER,J., SLOMAN,M. and DULAY,N. (1990). "An Overview of the

(20) (21) (22) (23) (24) (25) (26) (27) (28)

REX Software Architecture", Proc. of 2nd IEEE Computer Society Workshop on Future Trends of Distributed Computer Systems, Cairo. NEHMER,J., HABAN,D., MATTERN,F., WYBRANIETZ,D. and ROMBACH,D. (1987). “Key Concepts of the INCAS Multicomputer Project”, IEEE Transactions on Software Engineering, SE-13 (8). NIERSTRASZ,O.M. (1987). “Active Objects in Hybrid”, Proc. OOPSLA ‘87, Sigplan Notices, Vol 22, No 12, 243-253. PAGE-JONES,M. (1988). “Practical Guide to Structured Systems Design”, Prentice Hall International Editions. PURTILO,J. (1988). “A Software Interconnection Technology”, Computer Science Dept., University of Maryland, TR-2139,. RAJ,R.K. andLEVY,H.M. (1989). “A Compositional Model for Software Reuse”, The Computer Journal, 32 (4), 312-322. REX Technical Annexe (1989), ESPRIT Project 2080, European Economic Commission. STEIGERWALD,R. (1990). “Concurrent Programming in Smalltalk-80”, ACM Sigplan Notices, Vol 25, No 8, 27-36. WEGNER,P. (1987). “Dimensions of Object-Based Language Design”, Proc. of OOPSLA ‘87, 168-182. WEGNER,P. (1990). “Concepts and Paradigms of Object-Oriented Programming”, OOPS Messanger (ACM SIGPLAN), Vol. 1, NO. 1, 7-87.