and interconnection of heterogeneous legacy components have actually been raised ..... or a CAD tool) to be used within a distributed groupware environment.
System Services for Distributed Application Configuration Luc Bellissard, Fabienne Boyer, Michel Riveill, Jean-Yves Vion-Dury SIRAC Projet, INRIA Rhône Alpes 655, Avenue de l'Europe F- 38330 Montbonnot, France e-mail: [Luc.Bellissard, Fabienne.Boyer]@inrialpes.fr
Abstract The reuse of existing software components for the engineering of complex distributed applications is today a key issue in industrial development projects. Encapsulation and interconnection of heterogeneous legacy components have actually been raised as very fundamental issues and partial solutions have been proposed to overcome them such as the use of Object Request Brokers (ORB). However, these approaches do not address some of the issues raised by the construction of a complex distributed application from heterogeneous legacy components. This paper presents a set of configuration tools which intend to assist the application designer in the various stages of the application development life-cycle. This work has been carried out within the Olan project whose main result is an Architecture Definition Language for distributed application engineering and its runtime environment.
1. Introduction This work deals with distributed applications engineering. Such applications are built-up from a set of components, some of which integrate legacy software. The structure of the application is specified using an Architecture Definition Language[5][8][13] which is a high level declarative language that exhibits the application structure independently from the core implementation of components. This paper focuses on the definition and implementation of system services for the deployment of distributed applications defined through the use of such language. Deployment refers to the distribution of executable software, its installation and configuration on the operating computer nodes. The engineering of distributed applications is a complex issue and today several industrial technologies provide various ways to access remote data or to execute remote programs. Typical technologies, built usually as middleware layers, are for example object request brokers (ORB)[7] or message
busses[9]. Applications are constructed as a collection of independent software modules interconnected by those middleware. Although application modules can be implemented using different programming languages, the emphasis has not really been put on the integration of legacy software and their particular execution model. As a matter of fact, these middleware technologies impose their own communication model (client/server interactions for the ORBs or event/reaction in case of message busses). The goal of our work is to develop tools that try to automate as much as possible the generation of the executable image of an application, and that assist the deployment process of the application components on a distributed environment. The main contributions of this work are : • a language support belonging to the family of ADLs, that provides a declarative way of expressing the application configuration, in terms of composition of basic software units and deployment constraints for a distributed environment. • tools for the generation of the binary code of the distributed application and scripts for automating its deployment, • distributed system services to support the deployment procedure of the application The next section presents an overview of the abstractions of the Olan Configuration Language (OCL). Section 3 details the execution structures generated from an OCL description whereas section 4 depicts the architecture of the system services which compose the Olan Configuration Machine. This paper finally ends up with some related works and conclusions.
2. The Olan Configuration Language The Olan Configuration Language (OCL) belongs to the class of Architecture Definition Language[13] . Such
languages aim at clearly separating the programming phase of individual components from the configuration phase which provides a description of the global application in terms of these components. This latter phase aims at assembling and interconnecting components together according to various interaction schemas[3]. The central elements of OCL are the components and the connectors. An application is described as a hierarchy of interconnected components, the leaves of which are basic software units encapsulated in so-called "primitive" components. The nodes of this hierarchy are more complex components (namely "composite" components) which are constructed from interconnected components from the lower nodes/leaves within the tree. The object [1] that realizes and rules an interconnection is called a connector.
2.1 Components and Connectors Primitive components are the unit of software integration. They are known by their interface that describes the services of the component, both in terms of the services required as well as the services provided. Thus the functional dependencies of the component with the outside world are shown at the interface level. Services are described in terms of their signature in the Olan Interface Definition Language (OIL) which is basically a syntactic extension of the OMG’s IDL. As interfaces are expected to reflect as much as possible the behavior of the encapsulated pieces of software, OIL provides a specific type system which allows to express both the data flow (the signature of the services) and the control flow constraints (mainly the synchronization requirements) associated to the service (c.f. Table 1). The implementation of a primitive component describes where the encapsulated code can be found and its characteristics like the kind of software (source code, classes, libraries, executable, etc.) and the programming language. So far, primitive components can encapsulate C or Python modules or C++ and Java classes. The OMG IDL mapping to this languages (besides Python) is currently used to translate the native type system into the IDL one. Services
Data flow
Control flow
Provide
in/out parameters In parameters
No specific constraints (usually executed synchronously, like procedure calls) The encapsulated implementation contains an execution flow that handles the service processing in an asynchronous way. The encapsulated implementation is designed for synchronous external calls (e.g. procedure call ) The encapsulated implementation is designed for asynchronous external calls (e.g. event notification)
React
Require
in/out parameters
Notify
in parameters
Table 1. Interface Service Types
Connectors[13] are used to specify how components are connected to each others. The key idea of connectors is to explicitly describe the communication protocol of the component interactions[1]. These abstractions are compiled into runtime structures that handle the communication during the execution. Another important properties of connectors is to manage component heterogeneity and to adapt the control and data flows between a set of components. For example, control flow adaptation may be required when one component, requiring a service asynchronously, is bound to another component, providing this service through a synchronous call. The OCL compiler handles such properties and specializes the connector for execution. Data flow adaptation refers to the problem of interconnecting services with different signatures, notably containing different parameter types. In some cases, the adaptation can be derived by the compiler automatically (e.g. from the type string to a sequence of char). OCL Name syncCall
Caller Callee 1 require
1 provide
Protocol Synchronous communication
Implementation Local: method call IPC: ILU method call
Compatible signature Remote: ILU method call or data flow transformation asyncCall
1 notify
1 react
Local: method call from separate threads IPC : ILU asynch. Compatible signature method call or data flow Remote : ILU asynch. transformation method call
RandSync Call
1 require
1 to n provide
Like syncCall, single randomly chosen callee
Asynchronous Communication
like syncCall
Table 2. Some predefined Connectors
Table 2 presents some of the existing connector; a broadcast asynchronous call, and some specific connectors allowing the dynamic instantiation/deletion of components are also available.
2.2 Application Architecture The architecture of an application is basically composed of the declaration of the components instantiation schema and the specification of their interconnections, i.e. the dependencies between required and provided services of their interface as well as the communication pattern to be used at runtime. Composite components are the unit of structuring. They own an interface and an implementation like the primitive ones. The difference between both kind of components lies in the implementation part. A composite
implementation contains the specification of a group of components of any kind, that realize the interface of the composite component. The interesting fact about composite components is that the application designer can reuse part of an already defined architecture in order to build another version of an application. Existing software
Interface
At runtime, the configuration machine queries nodes about their actual management attributes and then decides where the components must be installed. Their context of execution is then set up to allow the global application to be launched.
3. Development Process and "automated" Software Generation 3.1 Overview of the Development Process
Connector Wrapper
Composite Implementation
Figure 1. Architectural Abstractions in OCL
2.3 Configuration parameters An innovative feature of OCL is the ability to express administration parameters in terms of both the execution node and the user for which components must be executed. This description is separated from the component definition allowing to define various distribution schemes while reusing the same components. The specification of administration parameters is based on a set of conditions which must be satisfied by the execution context of the component. For this reason, each component owns two management attributes structured with fields, one for characterizing the node and the other for the user. The conditions are boolean expressions associated to those fields, each of them expressing a constraint for the deployment of the particular component. In the future, additional management attributes will be considered. management attribute Host { string name ; // DNS name string IPAdr ; // IP address string platform ;// architecture string os; // OS type (posix, nt,) short osVersion; // OS version number long CPULoad ; // average load for the // past 10 minutes long UserLoad ; // nb of connected users } management attribute Owner { // characterization of the component owner string name; // user name long uid; // user id sequence grpId ; // list of groups } Example of conditions // All components on the domain .inrialpes.fr Host.name == "*.inrialpes.fr"; // components on an AIX Unix platform Host.os == "AIX4"; // Co-locate two sub-components (c1 and c2) c1.Host.name == c2.Host.name ; };
From an OCL description, the OCL compiler generates the classes for the components and the connectors (if these do not already exist) needed by the application. They are stored in a distributed repository. The compiler also generates a script (called the deployment script) that contains orders and guidelines for the deployment of the application in a distributed environment. OCL Compiler
Olan Configuration Machine
Produces OCL Description
Instanciates
Components classes
Connectors classes
Component objects
Application
Uses Connector objects
Deployment Script
Figure 2. The Development process of an Olan distributed application
The remainder of this section details the execution structures which are generated for components and connectors, as well as the interpretable deployment scripts.
3.2 Execution structures Basically, two kinds of structures can be distinguished at runtime : the components encapsulating legacy software and their binding to the underlying communication systems, and the connectors in charge of integrating a particular communication schema between components. In the current prototype, execution structures are implemented as objects programmed in the Python interpreted language[11]. Object orientation is there a convenient way to manage specializable classes of components and connectors. Let us now detail the components and connectors objects. 3.2.1 Component execution structure A component is represented by one main object, which is responsible for managing the interface with the encapsulated code as well as the communications with others components via connectors. The main characteristic
of such an object is to be configurable and its purpose is to allow dynamic positioning of the interconnections with other components as well as dynamic loading of integrated software. Figure 3 illustrates the structure of such objects. Component objects include two tables, inCall and outCall, indexed respectively by the name of the provide/react and require/notify services of the interface. Those tables act as binding tables between the stub/wrapper encapsulating the integrated software and the connector objects respectively. Component objects trap every call and redirect it according to the contents of the binding table. Calls to the component From Connectors Component Object Component Object Runtime Structure Runtime Structure inCall f1 f2 fn
outCall r1 r2 rn
To Connectors
Internal Calls from modules Stub Module 1
Stub Module n Stub
Wrapper Module 1
Wrapper Module n
Module 1
Figure 3. Software Integration at Runtime
In between the component object and the various integrated software (called modules), is the stub, that homogenizes parameters format, and the wrapper that knows how to access the encapsulated modules according to the kind of integrated software. Stubs and wrappers are automatically generated by the compiler. According to the kind of modules (or classes), the work to be performed by the programmer to have his code integrated, ranges from almost nothing to the explicit redirection of the outgoing calls to the wrapper. 3.2.2 Connector execution structure The main role of connectors is to bind a set of potential senders to a set of potential receivers for communication schemes based on service request or event notification broadcast. A connector is represented by two main kinds of Python objects: the service adapters (resp. notification) and the sender/receivers objects. The adapters represent both the entry and exit points for the connector structure. On a sender side, they provide a function that allows a given component to initiate a communication as described in OCL. On a receiver side, they have the ability to call a given function (representing either a provided service or a notification handler), provided by the component. The adapters are also in charge of executing the user-level code
which may have been added to the connector description (e.g. code for data flow adaptation). The sender/receiver objects are in charge of : • encapsulating the use of the communication system, • handling the possible control flow translations (e.g. when a sender asks for an asynchronous service request while the receivers provide the service in a synchronous way), and • handling remote communication according to the placement of the interconnected components. Let us detail the synchronous procedure call connector, which specification is described in Table 2. Service adapters are first created on each connected components side. Then, if those adapters are on the same context no sender/receiver object is created ; both adapters communicate through a method call. In any other case, two objects, the SCConnSender and the SCConnReceiver are created. In this example, both are ILU objects and they exchange an ILU reference in order to communicate remotely. Then they are linked with their respective service adapter. Information flowing through those objects is already marshaled data (done by the stub at the primitive component level). However, if data transformation code is specified at the OCL level, this code generated by the OCL compiler is inserted in between the sender’s service adapter and the sender object. This code unmarshals parameters, applies data transformation and marshals the new result. This example is rather simple because the syncCall connector handles a 1 to 1 connection. In case of a 1-N connection schema, the sender/receiver object structure is somehow more complicated because there must be some treatment for the delivery of the various results to the component that initiated the communication.
3.3 Deployment Scripts The deployment script (also called Configuration Machine script) contains a list of commands that can be executed by the Olan Configuration Machine (OCM). Those commands corresponds to the requests for the creation of components and connectors execution structures and the interconnection between the components, according to the architectural requirement expressed in OCL. The command for the creation of components requires several information from the script : the name of the component in order to be able to find the associated execution structure and the administration parameters that characterizes the
node and context of creation. The interconnection parameters contains the name of the connector to be instantiated and the list of components (and the services name) that must be bound together. Several other kind of commands can be found in the deployment script corresponding to every abstractions of the OCL, like the attribute assignment, the creation of composite structures, of collections, ...
to communicate with each other, for example at the deployment step when querying nodes or at the installation step when creating components remotely. However, the ORB is not used for the communication between components during the application execution (unless the application designer has specified its use in an interconnection). Interface
4.1 General Overview The OCM machine is in charge of creating and configuring components and connectors instances, according to the configuration constraints expressed in the deployment script produced by the OCL compiler. More precisely, the OCM performs the following tasks. • deployment of components: for each component, the OCM tries to find a relevant node able to host it, according to its placement constraints. • installation of components: the installation step consists in the creation of the components execution structures and the assignment of their initial parameters. Components can be created at various time: initially, at the beginning of the execution, or during execution if the OCL description contains dynamic components instantiation. • setting of interconnections: once components are created on the various nodes, the setting of interconnections consist in creating a connector execution structure according to the user-specified communication mechanism and the optional insertion of the code in charge of data flow transformation. As described in section 3.2.2, connector structure can be spanned on multiple nodes, depending on the component location. • support for the application execution: this final step allows users to launch an application execution and handles the authorized connections or withdrawals of users in a running session. The general architecture of the OCM relies on several abstract machines: the component machine in charge of managing the components execution structures, the connector machine in charge of handling the configuration of interconnections and a repository allowing a distributed access to the components core implementation and the OCL compiler generated structures. Each node able to host an application execution contains an instance of the OCM. It relies on an Object Request Broker when remote communication between computer nodes are required. The ORB is used whenever remote configuration machines need
Configuration Machine
Repository
4. The Olan Configuration Machine
Component Component Machine Machine Node
Connector Connector Machine Machine ORB (ILU)
Figure 4. Architecture of the OCM
4.2 Functions of the OCM Machine Three management functions are carried out by the OCM: • the management of the distributed environment, called a cell, • the control of the deployment and execution of a single distributed application, called a session, • the management of the part of a distributed application that execute on a given node for a given user, called a context. Cell management A distributed environment is managed by a set of Cell Servers, one per node for each cell. One particular Cell Server (called the Master Cell Server), is responsible for managing the join and the withdrawal of nodes inside the cell. A Cell Server provides features for the following tasks : • Instrumenting the local node with predefined sensors that return information corresponding to the management attributes. Information returned by sensors can be either static (e.g. the name, the IP address) or dynamic (e.g. the average load, the number of logged users). • Specifying policies for the evaluation of administration parameters contained in the OCL description. The criteria for eligible nodes may differ according to the cell administrators. • Managing the deployment of an application within the cell according to the scripts for the application. This task is performed through calls to the Session management level. Session management A given distributed application that is currently being executed is called a Session. A session is represented and managed by one Session server. The Session Server
provides services for the support of the installation and configuration of components and connectors of the application. Some of these services, like the creation of a component require the use of the Context Management level. Each time a user launches an application, (s)he specifies the name of the session in which (s)he wants the application to be executed. This may thus correspond to either the launching of a new session, or to the incoming of a new user into an existing session. More precisely, the launch of an application execution is managed through an additional script produced by the OCL compiler. Context management A Context represents the part of an application that executes for a given user on a given node. In other words, a context is an execution space for components, which ensures that components belonging to distinct users will not execute in the same address space, for protection reason. A context is managed by a Context Server, which is in charge of the actual creation and initialization of components within the context. A Context Server is also responsible for the creation and initialization of the parts of the connectors that involve the components it manages.
4.3 Experience and lessons learned A prototype implementation of the OCL compiler and Configuration Machine has been achieved using the Python language[11]. Using Python is of a particular interest for rapid prototyping due to facilities such as dynamic typing, reflexivity features, easy manipulation of complex structures such as lists, dictionaries, etc. Another major interest is the portability of Python code across various platforms (flavors of Unix or NT). However, the price to pay is the poor performance at runtime due to the interpretive approach. The configuration machine uses ILU, a CORBA compliant Object Request Broker, for its own communication purposes. However, ILU is not used for the actual execution of the application, except if the architecture contains explicit use of a connector based on ILU mechanisms. The component and connector structures are also implemented in Python. Stubs and wrappers may be implemented both in Python and in the native language of the integrated software modules. Finally, the implementation of the communication protocol within connectors depends on the kind of connector which is used. For instance, there are multiple implementations of a remote synchronous call: one using sockets, another one using sun RPC or ILU call. It should be noted that good performances at runtime were not expected from this experiment. The choice of the various implementation languages and tools were mainly motivated
by the objective of rapid prototyping. The lessons drawn from our experiments mainly concern: the feasibility of the approach; the ease of application configuration; the flexibility of the deployment procedure; the transparent use of a distributed environment. The prototype has been used for the construction of two applications: a cooperative document editor[2] and an electronic mail facility. The choice of these applications was motivated by the wish to address real-life scenarios which actually require heterogeneous components to be integrated within a distributed environment. The first scenario consists in transforming an existing single-user interactive application (e.g. a document editor or a CAD tool) to be used within a distributed groupware environment. No changes can be applied to the code of the application itself (as usually only binary code is available). A way to achieve this goal consists in replicating the application on each user node, and building a coordination function defined as a set of cooperating components also replicated on each node. These components communicate together to achieve the control of the coordination between them, but they are the only one allowed to interact with the instance of the application of their node. The second scenario consists in extending an existing application (in this case an electronic mail browser) with additional facilities, acting autonomously on behalf of the end-user (e.g. for filtering and/or forwarding messages according to parameters customized by the user). Here again, the application itself cannot be changed and new functions are implemented as a set of cooperating components (also called agents here because of their specific role) which interact with existing software modules (i.e. the sendmail program, and the Netscape mail browser in this scenario). In both case, the Olan environment has proved to be helpful for the following reasons: • the OCL compiler greatly aids in providing wrappers to encapsulate existing binary code thus integrating legacy applications in a distributed environment (e.g. the Netscape browser and the editor in the previous scenarios) • the Olan Configuration Machine also revealed to be very helpful in the implementation of the deployment process of the distributed application configurations. In the previous scenarios, nothing related to the distribution has to be implemented by the component programmer. Everything concerning distribution is externalized and the remote communications are handled by connectors.
In addition, it should be noted that an OCL description facilitates the reusability at the architecture level. This is a major advantage as it allows easy customization of an application for a specific use. Customization can be achieved in two ways: at the component level, to provide new facility, functionally equivalent to the former one, but implementing new policies; at the connector level, to change the communication schema between a set of interrelated components. For example, in the cooperative editor application, the component in charge of implementing the floor-passing policy can be changed on demand. Moreover, the same architecture may be reused to extend an existing CAD application towards a groupware environment. This does not to redevelop the whole application from scratch.
5. Related work Mechanisms intended to mediate invocations between remote objects are adopted increasingly in distributed applications development. Object Request Brokers such as CORBA[7] or Microsoft’s Distributed Component Object Model (DCOM)[10] are the leading references but some other mechanisms such as the message busses[11] are also interesting to consider. ORB-based systems provide features for the integration of heterogeneous software that can be accessed remotely in a transparent way by the application programmers. The goal of such systems is to decouple the implementation of components from their use through their interface, which is the only information that remote client programs are aware of. One important issue is the mapping of the common interface description formalism (described with an Interface Description Language, IDL) to the various programming languages used for implementation purpose. Moreover, at runtime, the communication between objects is based on a client server model of interaction where clients must first have the knowledge of the identity of the server objects. Message busses[9] are complementary to the ORB approach to some extent because the execution model of software components complies with asynchronous (event-based) interactions. More precisely, anonymous communication is allowed: the software components interact with each other without being aware of their identity and the existence of each other. This high level of flexibility is a main advantage when programming distributed applications that involve multiple users which may connect dynamically to the application during its execution. CORBA and DCOM provide some degree of configuration. A components can be easily replaced with a new version using the interface inheritance capability in CORBA or the
aggregation and delegation mechanisms in DCOM. The distribution of components can be, to some extent, configured later on, more or less independently from the components programming. Finally, there are some ways for an object to dynamically communicate with unexpected objects (i.e. unknown at compile time) using CORBA Dynamic Invocation Interface or DCOM IUnknown interfaces. However, those solutions look like aftermath added features. At the time being, CORBA or DCOM applications cannot be considered as "configurable" because the overall architecture of an application is nowhere exhibited, which makes the configuration of its components hard to evolve without a deep knowledge of the overall application structure. The communication between objects or components is hard coded, hidden into their implementation, preventing any change to be easily performed. Finally, the deployment of the application components on a computer network is performed manually or, at best, hard-coded in the component. Several projects in the area of distributed software engineering have adopted the two-level approach of distributed programming: one for the core implementation of components, and the other for the application architecture (also called programming in the large). Conic[5] and Darwin[6] are especially dedicated to distributed applications but they hardly help in the integration process of heterogeneous components and changing communication protocols is not easy. Polylith[8] has focused on the management of components heterogeneity but the application architecture does not reflect the instantiation schema of components and the change of a communication schema between components relies on the availability of system services called software busses. UniCon[13] introduces the connectors in order to easily configure the communication, but they hardly describe the components instantiation schema and it does not really focus on distributed applications. The Olan project has adopted a similar approach but we have tried to integrate many aspects of architecture description in a single configuration language (e.g. integration of legacy software, description of the dynamic behavior of an architecture, management attributes, ...), and we have proposed a complete environment for the generation of the application code and the deployment on heterogeneous distributed environments.
6. Conclusion This paper has described the Olan Configuration Machine, a set of system services for handling the configuration of distributed applications. Applications that benefit from this support are described with an architecture definition language named OCL. This description is then compiled to generate execution structures and configuration scripts handled by the Olan Configuration Machine. The OCM supports three kinds of actions: • the encapsulation of heterogeneous software components, from the point of view of both their execution model and the programming language through the use of an homogeneous component model, • the computer-aided deployment and installation of components within a distributed environment, and • the set up of component interconnections using particular communication objects called connectors, whose role is to define the components binding, communication properties, and the encapsulation of the target communication mechanism. This experiment primary goals are to demonstrate the opportunity and the benefits of coupling an architecture definition language to a configuration support in a distributed environment in order to ease the engineering of application integrating legacy software pieces. Compared to other research projects, we have tried to integrate many aspects of distributed programming within the architectural description and, most of all, the Olan environment brings solutions to the problem of deploying, installing heterogeneous components and interconnecting them with the use of existing remote communication systems. The chosen approach was thus to homogenize the programming and execution model of components through the use of a uniform component execution structure and to have them communicate in a configurable way using connectors. From that respect, the first experiments have demonstrated the feasibility of this approach as well as the gain obtained in terms of ease of use for the application designer. However, the poor performance due to the generated execution structures is still an obstacle to a large use of such an integration technology. Multiple layers must be crossed whenever components communicate. This is part of the work being currently undertaken in the project, trying to find solutions to prevent the systematic homogenizing of execution and communication models. Another future aspect of our work includes the dynamic reconfiguration of an application, i.e. the way a given configuration may be changed at runtime with minimal penalties on the running application.
Acknowledgment We would like to make a special thank to Roland Balter for its careful reading and constructive comments.
7. REFERENCES [1] Allen R., Garlan D., "Formal Connectors", CMU Tech. Report CMU-CS-94-115, School of Computer Science, Carnegie Mellon University, Pittsburgh, PA 15213, USA, March 1994. [2] Bellissard L, Ben Atallah S., Kerbrat A., Riveill M., "Component-based Programming and Application Management with Olan", Object Based Distributed and Parallel Computation Franco-Japan Workshop (OBDPC’95), Eds. Briot J.P., Geib J.M., Yonezawa A., Lecture Note on Computer Science, LNCS 1107, Springer Verlag [3] Bellissard L., Ben Atallah S., Boyer F., Riveill M., "Distributed Application Configuration", in Proc. of the 16th IEEE Intn’l Conference on Distributed Computing Systems (ICDCS’96), Hong Kong, April 1996 [4] Janssen B. Spreitzer M.., "ILU 2.0alpha10 Reference Manual", Xerox Corporation Palo Alto CA, Feb. 1996, (http:\\ftp.parc.xerox.com\ilu) [5] Kramer J., Magee J., Sloman M., "Constructing Distributed Systems in CONIC", IEEE Trans. Software Engineering, vol.SE-15(N.6), June 1989, pp.663-675. [6] Magee J., Dulay N., Kramer J., "Regis: A Constructive Development Environment for Distributed Programs", IEE Distributed Systems Engineering Journal, vol.1(N.5), Dec. 1994, pp.304-312 [7] Object Management Group, "The Common Object request Broker Architecture", Object Management Group, Revision 2.0, 1995 [8] Purtilo J. M., "The POLYLITH Software Bus", ACM TOPLAS, vol.16(N.1), Jan. 1994, pp.151-174. [9] Reiss S., "Connecting Tools using Message Passing in the FIELD Environment", IEEE Software, pp. 57-66, July 1990 [10] Rogerson D., "Inside Com", Microsoft Press, One Microsoft Way, Redmond WA 98052-6399 USA, 1997, ISBN 1-57231-349-8 [11] Rossum Van R. "Python Reference Manual", Dept. AA., CWI, P.O. Box 94079, 1090 GB Amsterdam, NL, Release 1.3, Oct. 1995 (http:\\www.python.org\) [13] Shaw M., DeLine R., Klein D. V., Ross T. L., Toung D. M., Zelesnik G., "Abstractions for Software Architecture and Tools to Support Them", IEEE Trans. Software Engineering, vol.SE-21(N.4), April 1995, pp. 314-335.