Modular Construction and Composition of Distributed Software ...

5 downloads 13559 Views 250KB Size Report
which allows transparent customization of actor behav- iors. Speci cally, connector policies are implemented by coordinating meta-level customizations over a ...
Modular Construction and Composition of Distributed Software Architectures Mark Astley and Gul A. Agha Department of Computer Science Univ. of Illinois at Urbana-Champaign 1304 W. Spring eld, Urbana, IL, 61801, USA fastley, [email protected]

Abstract A complete speci cation of a distributed software architecture describes two di erent aspects. First, it decomposes the software into its components and their interconnection. Second, it speci es the policies that are required to manage an architecture. Such policies are dependent on the nature of the execution environment. They are complicated by requirements such as heterogeniety, availability, and adaptability. Embedding architecture management policies in components and connectors sacri ces modularity. We describe an architecture description language, the Distributed Connection Language (dcl), for specifying distributed software architectures. Components in dcl are concurrent and distributed, and implement application functionality. Connectors specify policies governing component interactions and resource use. Thus connectors may specify load balancing or fault-tolerance policies. We base our approach on the Actor model and a meta-architecture which allows transparent customization of actor behaviors. Speci cally, connector policies are implemented by coordinating meta-level customizations over a collection of actors. We describe component and connector abstractions as they are speci ed in dcl, and illustrate their use by way of several examples.

1. Introduction The complexity of modern distributed systems has lead to an emphasis on compositional approaches for system development. For example, middleware solutions such as the Common Object Request Broker Architecture (CORBA) [10] and Java's Remote Method Invocation (RMI) [13] have incorporated compositional design by separating functional aspects of a system

(e.g. objects) from the mechanisms used for interconnection, e.g. remote procedure call through stubs and skeletons. Separating objects from the policies which govern their interaction simpli es debugging and makes reuse feasible. In particular, the protocols required for interaction need not be hard-coded in objects. This allows objects and protocols to be independently tested and later composed into runnable systems. Moreover, as requirements change, existing architectural elements may be modularly replaced by new elements with appropriate properties. For example, a two-phase commit protocol may be the initial choice for coordinating interactions in a distributed database architecture. If architectural constraints later change, for example requiring stricter reliability properties, modular design allows us to replace a two-phase commit with a threephase commit without a ecting client code. Approaches such as CORBA and RMI allow for more ecient system development, but still lack tools for verifying that compositions are semantically correct: stubs and skeletons may be used to connect objects but do not guarantee that interfaces are invoked properly. To verify correctness and reason about composability, researchers have introduced the notion of architecture description languages (ADLs) which factor systems into a collection of components, which encapsulate computation, and a set of connectors, which describe how components are integrated into the architecture [11]. ADL speci cations de ne the basic structure of a system as well as the semantics of each architectural element. Composition operators in ADLs are used to specify larger systems from smaller components and verify the semantics of the resulting composition. Current ADLs provide for modular speci cations of components and their interconnection. Although such modularity is useful for specifying the basic functionality of a given application, distributed systems

Encryption Policy

CCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCC BBBB BBBBBBBB CCCCCCCCCCCCCCCCCCCC 555 BBBBBB BBBB BBBBBBBB CCCCCCCCCCCCCCCCCCCC 555 BBBBBB BBBB BBBBBBBB Cluster Resource CCCCCCCCCCCCCCCCCCCC 555 BBBBBB BBBB Management Policy CCCCCCCCCCCCCCCCCCCC 555 BBBBBB BBBB CCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCC BBBB CCCCCCCCCCCCCCCCCCCC BBBBBBBB CCCCCCCCCCCCC BBBBBB BBBB CCCCCCCCCCCCCCCCCCCC BBBBBBBB CCCCCCCCCCCCC BBBBBB BBBB CCCCCCCCCCCCCCCCCCCC BBBBBBBB BBBB CCCCCCCCCCCCC BBBBBBBB BBBBBB BBBB CCCCCCCCCCCCCCCCCCCC BBBB BBBB 555 555 BBBBBB BBBB BBBBBBBB CCCCCCCCCCCCC BBBBBBBB BBBBBBBB BBBBBB BBBB BBBBBB BBBBBBBBBBBB BBBBBB BBBB 555 555 BBBBBB BBBB BBBBBBBB CCCCCCCCCCCCC BBBBBBBB BBBBBB BBBB BBBBBB BBBB 555 555 BBBBBB BBBB BBBBBBBB CCCCCCCCCCCCC BBBBBBBB BBBBBB BBBB BBBBBB BBBB 555 555 BBBBBB BBBB Unsecured Dedicated BBBBBB BBBB BBBBBB BBBB Network Cluster Server

Clients

A Distributed Client-Server Architecture:

Figure 1. The server is executed on a dedicated cluster for high-availability. Clients communicate with the server over an unsecured network. Architectural policies manage the use of cluster resources by server components, and ensure secure client-server interactions.

policies requires the development of a new model of components and connectors; such a model must expose resource use and locality, and provide new compositional operators for asserting policies over components and connectors. Moreover, the operators should have a composable semantics so that incremental reasoning may be used to verify architectural correctness.

have more complex requirements such as heterogeneity, availability, and adaptability. Such requirements result in complex management policies that are not isolated to the interconnections between components; instead the policies assert properties of the relationship between components, connectors, and the execution environment. As a simple example, consider a distributed client-server architecture (see Figure 1). While connectors de ne the mechanisms by which clients are matched to the server, this architecture requires two policies for e ectively managing the architecture:  Cluster Management: The server executes on a dedicated cluster for high-availability. A cluster resource policy controls the allocation of cluster resources among server components.  Secure Interactions: Clients interact with the server over an unsecured network. An encryption policy is enforced over connectors linking clients and servers in order to provide secure interactions. Policies such as cluster management and encryption assert properties required by the execution environment, and are orthogonal to the functional behavior of the system. It is now well understood that embedding interconnection mechanisms within components sacri ces component modularity. We argue that embedding architecture management policies within the components and connectors themselves similarly sacri ces architectural modularity. Separating architectural

The remainder of this paper describes the Distributed Connection Language (DCL), an ADL which

emphasizes component resource management and deployment for distributed software architectures. In Section 3, we introduce modules for the linguistic speci cation of components and their interconnection. Modules encapsulate collections of Actors [1] which are an atomic unit for distributed software architectures. Interactions between modules are modeled as asynchronous messages between actors. In Section 4, we describe protocols which provide a representation for connectors. Protocols implement connector policies by accessing an open implementation (cf. [8]) of the actors within a module. In particular, a meta-architecture allows the customization of basic actor operations. Metalevel customizations may be composed to allow multiple policies to be applied to components. Both modules and protocols are illustrated by a number of examples. The last section discusses future directions. 2

2. Related Work

a complete behavioral speci cation of how events from one port are translated into events on another port. There are two main di erences between dcl and Wright and Rapide. First, both Wright and Rapide are designed for formal veri cation and testing of architectures early in the design process. For example, the byproduct of a Rapide architecture is the causal history of its events, which is used to analyze system behavior. Rapide tools exist which allow analysis of causal histories for debugging and general understanding. Similarly, Wright speci cations use formal analysis of CSP code fragments to allow the validation of several features of an architecture such as consistency (component ports must match connector roles, port speci cations within a component must not be contradictory, etc.), and deadlock freedom (port-role interactions do not hang, role-role interactions are deadlock free, etc). In contrast, dcl speci cations currently provide little support for formal reasoning. Rather, our preliminary goal is to increase the expressibility of ADLs relative to component integration as well as support a language which may be mapped directly to implementations. Nonetheless, formal analysis is a desirable feature and is the focus of ongoing work. A second feature which di erentiates dcl is the emphasis on connection policies which manage low-level integration issues. Wright and Rapide abstract away most of the behavior of components and focus on interaction mechanisms. Practical experience has shown that these issues are not independent and changes to one often imply changes to the other, usually at great cost [6]. Thus, dcl abstractions represent an attempt at integrating both connection and deployment management policies within a single, uniform framework.

Several architecture description languages have been proposed in the literature. Of these languages, Rapide [9] and Wright [3] are useful representatives due to their formal nature and the scope of their speci cations. Thus, rather than detail the features of each of the many existing ADLs, we describe the approach used in Rapide and Wright and refer the reader to [4] for an interesting survey of architecture description languages in general. Rapide is an object-oriented language designed for event-based prototyping of distributed software architectures. A Rapide architecture contains a set of module speci cations called interfaces which de ne a collection of named entry points. The behavior of an architecture is de ned by a set of connection rules which determine how events are transmitted between interfaces. The set of formal constraints for an architecture restricts the patterns of events transmitted by connection rules. Formal constraints placed on interfaces restrict local event patterns, while those placed on entire architectures restrict all event patterns in the architecture. The formal constraints speci ed in an interface provide a \contract" describing the context of an interface in an architecture. This represents the simplest form of connection policy between two modules: that implied by their respective local constraints. These default connection policies may be augmented with formal constraints which ensure global properties. While Rapide de nes architectural computation and connection in terms of event patterns, the Wright language de nes architectural structure in terms of extensions to Communicating Sequential Processes (CSP) [7]. A Wright architecture consists of an interlinked set of components and connectors. Wright components are speci ed by an interface and a computation. An interface describes a xed set of ports through which the component may interact. A computation describes component behavior in terms of interactions triggered at ports. Each port also de nes a behavior for handling interactions. For example, a lter component would de ne an input port with the behavior of receiving data, an output port with the behavior of sending data, and a computation with the behavior of computing an output based on the input. A Wright connector de nes an interaction pattern between a set of ports. A connector speci cation consists of a set of roles, which describe the behavior of each participant in the connection, and glue which describes how the participants are linked to de ne an interaction. A role represents the behavior expected by an interface port which assumes the role. The glue of a connector is

3. Specifying Distributed Software Architectures Distributed architectures are speci ed in terms of a set of components and their interconnection. We model components as hierarchical collections of Actors [1]. Actor computation implements the functional behavior of components while actor interactions (i.e. asynchronous message passing) de ne the mechanism by which component services are invoked. In dcl, components are de ned by modules. In particular, modules specify an initial set of members (e.g. actors or submodules) and a control interface for creating connections to the module. Module connections are handled by a distinguished subset of actors called liaisons. The control interface for a module de nes the mechanism by which liaisons are assigned to handle new connections. In this section, we describe actors and their use in 3

specifying modules. Connectors and protocols are described in the next section.

Manager

Promote Liaison

Interactions Between Components

Create Actor

3.1. Actors

We use the Actor model as a basis for describing computation in a distributed architecture. Actors provide a general and exible model of concurrency which may be used as an atomic unit for building typical architectural elements including procedural, functional, and object-oriented components. Moreover, actor interactions may be used to model standard distributed system communication mechanisms such as remote procedure call (RPC), transactions, and other forms of synchronization [2, 12, 5]. Conceptually, an actor encapsulates a state, a thread of control, and a set of procedures which manipulate the state. Actors coordinate by asynchronously sending messages to one another. Each actor has a unique mail address and a mail bu er to receive messages. Actors compute by serially processing messages queued in their mail bu ers. An actor blocks if its mail bu er is empty. While processing a message, there are three basic actions which an actor may perform that a ect the computational environment:   

Computing Actor

Liaison

Encapsulated Interaction

Figure 2. Components are organized hierarchically in terms of actors.

Conceptually, components are characterized by three features (see Figure 2): 

send messages asynchronously to other actors; create actors with speci ed behaviors; and become ready to receive the next message.



Communication is point-to-point and is assumed to be weakly fair: executing a send eventually causes the message to be bu ered in the mail queue of the recipient although messages may arrive in an order di erent from the one in which they are sent. Actor mail addresses are rst class entities which may be communicated within messages. The create primitive creates a new actor with a speci ed behavior. Initially, only the creating actor knows the name of the new actor. However, the name of the new actor may be communicated to other actors as described above. In this paper, we represent actors as concurrent objects executing on a xed, named collection of physical nodes. That is, an actor consists of a private local state, a set of methods, and the name of the machine on which the actor resides. Message passing is viewed as the asynchronous invocation of methods.



3.2. Components

Components encapsulate a collection of actors and/or a collection of interlinked sub-components. 4

Encapsulated Namespace: The actors within a component comprise a closed namespace. That is, with the exception of certain special members, actors within a component may only interact with other actors in the same component. Similarly, messages which originate outside a component are never allowed to be delivered to the actors within a component (except as described below). Moreover, new actors created by component members remain logically within the same component (although they may be physically distributed). Interface: The interface of a component is de ned by a dynamic subset of its members called liaisons. A liaison is a special actor which may send messages to and receive messages from external actors. Liaisons are appointed by the component manager (see below) and are the only actors that may communicate using external addresses. That is, although external addresses may be shared among component members using messages, only liaisons may target messages to external addresses. Similarly, external messages targeted to internal, non-liaison actors are never delivered. Manager: Each component contains a unique manager which initializes the state of the component, and facilitates the instantiation of connections for external interactions. Connections between components are created in a two-step process. In the rst step, each component manager promotes one or more members to handle the connection (making these members liaisons if they aren't already). In the second step, local liaison addresses are exchanged among the components participating in the interaction. Upon receiving a

\default" connections. Thus we force all connections to utilize the connect module operation. A connection request takes the form of an interface which describes the collection of actor addresses that are required for one participant in a connection. A module operation may use instanceof to infer the type of an interface and act appropriately. Collections of interfaces are organized into connections, which de ne bindings between interface addresses. As an example of a connection speci cation, consider a web server which uses an HTTP connection to interact with clients. We might specify an HTTPConn connection structure as follows:

set of external liaison addresses, a manager distributes these addresses to the appropriate local liaisons. Representing components as encapsulated collections of actors allows for scalable computation and exible interfaces. For example, locality, concurrency and other eciency trade-o s may be tuned by specifying the placement, number and granularity of component actors. Similarly, interfaces may be dynamically extended by creating new liaisons to handle new connections. Component managers control the interface of components and provide a mechanism for initializing and coordinating members. Linguistically, components are speci ed as modules. A module de nes a component type and provides an abstract description of the behavior of the component manager. In particular, a module speci cation consists of the following elements: 



connection

Init: Each module may specify initialization code

which is executed when the module is instantiated. Typically, this section is used to create an initial set of module members. Members may be actors, other modules (called sub-modules), protocols (i.e. connectors), or connections (see below).

g

HTTPConn f // List member interfaces HTTPServerInterface server; HTTPClientInterface client; // Bind locals and remotes bind server.rClient to client.lClient; bind client.rServer to server.lServer;

HTTPServerInterface

and HTTPClientInterface are

interface structures which de ne endpoints of the connection. The bind keyword indicates a binding between

actor names in each interface. Bindings between interfaces de ne the set of addresses to be exchanged by component managers during a connection, although this exchange is handled implicitly by the system. The interface structures used in the HTTPConn connection would be speci ed as follows:

Operations: Operations de ne a control interface. Every module must de ne a connect operation which is used to instantiate a new connection with a module. Other operations may be de ned in order to provide more extensive interaction with the module.

interface HTTPServerInterface f local lServer; remote rClient;

The init and operations sections of a module completely de ne the behavior of the component manager. In particular, the state of the manager is represented by the de nitions in the init section, while interface management and other high-level manager behavior is speci ed by module operations. Unlike similar languages, there are no static connections between components in dcl. That is, every module connection must be explicitly instantiated in the init section or as a result of a module operation. Although at rst this may seem like a serious limitation, note that static connections are merely a convenient way of abstracting over certain aspects of module initialization1. Our goal is to make these connection activities explicit, even in the case of

g

interface HTTPClientInterface f local lClient; remote rServer; g

The local keyword represents a local address which is bound within a connect operation. The remote keyword is a placeholder for a local address in another interface which will be bound by another manager. A remote address is used by a local liaison to send external messages. Once bound, a local address is xed for the life of the interface. The dcl code for a web server module which accepts HTTPServerInterface structures is given in Figure 3. In the init section, the web server creates a le server which holds HTML les. The connect operation only accepts requests for new HTTP connections. Upon

1 This isn't quite true. Static connections are also useful for performing compile-time type checking. Note that we can easily extend modules with an \exports" section which lists a set of interfaces initially visible outside a module. These interfaces would be used to type check the initial connections applied to the module.

5

interactions between sub-components. This abstraction is necessary to allow elements of architectures to be reused in di erent contexts. Connectors, on the other hand, de ne the policies which manage an architecture according to the constraints of the execution environment. That is, connectors manage interactions between components and underlying system services (see Figure 4). The policies implemented by connectors are motivated by features of the execution environment. For example, two components which interact often should be placed on the same machine to take advantage of locality. Similarly, two components which exchange sensitive data over a public network may require encryption for security purposes. As a result, connectors enforce two types of constraints over components: constraints on interactions between components, and constraints on allocation and management of resources. Recall that interactions between components are expressed as patterns of messages between liaisons. Thus, constraints such as encrypting interactions may be implemented by enforcing protocols over liaison interactions. Resource utilization, however, is expressed implicitly by the behavior of all actors within a component. Moreover, component encapsulation boundaries hide the number and composition of internal actors. Thus, constraints such as exploiting locality are enforced by applying a generalized customization which is adapted to the actual distribution of actors within a component. Connectors enforce constraints by customizing the behavior of component actors. By customizing basic actor operations (i.e. send, create and ready), highlevel policies may be enforced over all actors within a component. Connectors are characterized by three features (see Figure 5):

module WebServer f init f g

// Instantiate members FileSysMod docServer =

new FileSysMod();

operation connect(interface I) f if (I instanceof HTTPServerInterface) f

g g

g

HTTPServiceActor newActor = HTTPServiceActor(I.remoteClient); promote newActor; assign newActor to I.server; FileAccessConn newFileCon = new FileAccessConn(); newFileCon.fileClient.client = I.server; docServer. connect(newFileCon.fileServer);

else Signal Error

Figure 3. A WebServer component.

receiving an HTTPServerInterface structure, a new HTTP actor is created to handle the connection and linked to the le system. The syntax promote newActor is used to designate an actor as a liaison for the module. The le server is connected to HTTP actors by calling docServer.connect with an interface de ned in FileAccessConn (not shown). The assign keyword is used to resolve local addresses in interfaces. In the example in Figure 3, the local interface address I.server is assigned to the new actor referenced by newActor. Upon accepting an interface, all local addresses must be bound before the connect operation completes. Because local addresses may be bound in an arbitrary order, a liaison in one module may attempt to send a message to a remote address before it has been bound locally by another manager. In this case, all such messages are queued by the system and forwarded when the appropriate local address is bound.



4. Customizing Architectures Components and their interconnection, as discussed in the previous section, de ne the functional behavior of an architecture. In particular, components abstract over the actual deployment of a system emphasizing, rather, the decomposition of architectures into



6

Roles: A role is a speci c customization applied to one or more liaisons in a component. Roles may be used to implement protocols by customizing the behavior of liaisons involved in a particular interaction. For example, an encryption protocol may be implemented by customizing the \send" behavior of one liaison (e.g. to encrypt outgoing messages) and the \receive" behavior of another (e.g. to decrypt incoming messages). Roles are installed explicitly on a set of liaisons when a component is composed with a connector. However, dynamically created liaisons are not automatically customized by the same roles. That is, new roles must be explicitly installed on new liaisons. Context: A context customizes all actors within a component and are automatically installed on any

Interactions Between Components

Actors Component

Sub-Component

Connector Managing Resource Usage

Connector Managing Interactions

Invoke Distributed Services

Physical Node

Figure 4. Connectors customize the use of system services by component actors.



dynamically created actors. Contexts are used to manage the allocation of resources. For example, a local load balancing strategy may be implemented by customizing the \create" behavior of all actors within a component. Manager: Connectors de ne a manager for coordinating roles and contexts. In particular, roles and contexts are active customizations which may synchronize or share state by sending messages to the manager. For example, a global load balancing strategy can be implemented by using the manager to coordinate each stage of a consensus protocol for choosing the location of new actors. Each role or context is implicitly instantiated with the address of their manager.

Internal Actors

=

send, create, ready operation

Component Liaisons

Role

Manager 1111 0000 0000 1111 0000 1111

Context

Connector Coordination

Figure 5. Connectors customize component behavior with roles and contexts.

A protocol is a linguistic construct used to specify a connector. A meta-architecture provides the mechanisms by which role and context customizations are applied. The role and context keywords are used within protocols to de ne meta-level replacement behavior. We describe the actor meta-architecture and the construction of protocols in the remainder of this section.

a new actor blocks the creator until the system obtains the address of the new actor. We model this relationship by viewing each actor as a state machine which has an associated system state for each action (see Figure 6). The default state is the Proc Msg state which indicates that the actor is processing a message. An actor remains blocked while in a system state, and resumes when the appropriate arc is traversed from the system state back to the Proc Msg state. Each state transition is de ned as follows:  transmit(msg): An actor send is translated into a transmit transition with msg, a message structure which encapsulates the method, arguments, and destination of the message. By default, this transition invokes the underlying network service to asynchronously transmit the message to the tar-

4.1. Customizing Actor Behavior

Actors may perform three actions which a ect the external environment: send a message, create a new actor, or become ready to process a new message. Each of these actions can be viewed as invoking a service in the underlying system which blocks the actor until the action has been completed. For example, sending a message blocks the actor while the message is delivered to the network transport layer. Similarly, creating 7

dress2 . Proc Msg

method ... { . . dest.meth(...) . . a = create(b,m) . . }

 transmit(msg)

newAddress(a)

System Services

ready

deliver(msg)

Figure 6. Actor behavior represented as a state machine. Each transition blocks the actor until the system returns control.

get actor. 

continue: This transition is invoked to return control to an actor after processing a transmit. Note that this transition only indicates that the corresponding transmit request has been processed, not that the message has actually been received by the target.



ready: The actor ready operation is translated



deliver(msg): This transition is used to deliver



to an actor following a create transition, where a is the address of the newly created actor.

The transmit, ready, and create transitions de ne the system interface invoked by an actor, while the continue, deliver and newAddress transitions de ne the actor interface invoked by the system. A role or context customizes actor interactions by rede ning the transmit, ready, and create transitions. These customizations are modeled as new states in the actor state machine (see Figure 7). We view the Customization state in Figure 7 as an extension to the Proc Msg state which de nes a set of methods to invoke in place of certain system operations. For example, a create transition invokes the create method in the Customization state. As before, an actor may not continue processing the current message (or receive a new message to process) until the appropriate transition occurs from the Customization state back to the Proc Msg state. The methods de ned in the Customization state may also invoke operations which cause a transition to the system state as before. The syntax send(msg) may be used to forward an existing message structure. As with the Proc Msg state, each transition from the system state to the Customization state is used to return from a particular operation. In particular, a deliver transition from the system state to the Customization state invokes an arbitrary method in the Customization state. The receive method shown in Figure 7 is used to receive messages which specify methods to invoke on the Proc Msg state (see below). A role or context speci cation is similar to an actor speci cation with certain methods reserved for handling interactions with the base actor. As a simple example, consider the encryption of messages between liaisons as described above. Figure 8 illustrates how we might implement this behavior as a role. In this example, the transmit method rst encrypts the outgoing message and then sends it to the destination actor. The continue command at the end of the method returns control to the underlying actor once the message has been sent. The syntax target indicates that the sent message should be delivered to the EncryptRole on the target. This syntax is used to allow the system to properly deliver a message when

continue create(b,m)

newAddress(a): This transition returns control

into a ready transition which alerts the underlying system scheduler that this actor is ready to process a new message. By default, if messages are waiting to be processed, the system scheduler delivers the next available message. Otherwise, the actor is blocked until a new message arrives. a new message to an actor where msg is a message structure. Upon invoking deliver, the system automatically unwraps the message and invokes the appropriate method on the target actor. This transition is paired with the ready transition.

create(b,m): An actor create is translated into a

create transition with b, the behavior (type) of the new actor, and m, an optional argument naming the physical machine on which to create the new actor. The argument m indicates a request, rather than a requirement. That is, a new actor is always created but it may not reside on the machine requested. By default, the system creates the new actor on the speci ed machine and returns its ad-

2 In most systems, remote creation is a high-latency operation which is usually hidden by creating a local proxy which eventually forwards messages to the remotely created actor. In this paper, we are mainly concerned with expressibility rather than performance. Thus, we assume any such latency hiding is handled transparently by the underlying system services.

8

Proc Msg Customization method ... { . . dest.meth(...) . . a = create(b,m) . . }

transmit(msg) method transmit(msg) { ... } create(b,m) ready

transmit(msg) create(b,m) ready

method create(b,m) { ... } method read() { ... } method receive(msg) { ... }

System Services continue newAddress(a) deliver(msg)

continue newAddress(a) deliver(msg)

Figure 7. Customizing actor behavior. Customizations are represented by a new state in the state machine which intercepts system service transitions.

method invocation by the EncryptRole at one actor on the EncryptRole at another actor using the syntax target. The system determines the depth of the target role and automatically adjusts the message structure delivered to the top state. The receive method is invoked at each level to receive the message and may be delivered to the next level as appropriate. The solid path in the gure indicates a method invoked on the base actor at the target.

role EncryptRole f method transmit(message msg) f actor target = msg.dest; EncryptStruct encrypted =

encrypt(msg); target. receiveEncrypted(encrypted);

g

continue();

method receiveEncrypted (EncryptStruct origMsg) f deliver(decrypt(origMsg)); g

4.2. Protocols

The roles and contexts which de ne a connector are organized into protocols. As with modules, a set of operations de nes the behavior of the connector manager. Protocol operations are used to install a connector on modules as well as allow roles and contexts to synchronize through the manager. In particular, the variable mgr is implicitly bound in each role or context to the managing protocol. Protocols are installed on modules by providing the addresses of liaisons and/or a reference to the module itself. Figure 10 provides a speci cation of an encryption protocol which makes use of the encrypt role de ned above. The installEncrypt operation installs an EncryptRole on a pair of liaisons. The apply block guarantees atomic installation over all entries in the block. Each entry consists of a role or context speci cation and its corresponding liaison or module reference, respectively. As an example of a protocol which installs a context, Figure 11 de nes a protocol which implements a simple global load balancing strategy. Note the use of the mgr variable to synchronize through the manager. Note also that the creating actor is momentarily blocked while

g

Figure 8. Encryption and decryption of messages between liaisons represented as a role.

multiple roles or contexts are installed on a single actor. When the receiving actor is ready to process a new message, the system invokes the receiveEncrypted method on the role customizing the receiver. This method decrypts an incoming messages and delivers it to the base actor. In many cases, several customizations may be required on a single actor. These customizations are composed by adding their states, in the order of application, to the actor state machine. Messages delivered to actors with multiple customizations are automatically modi ed so that the correct method is invoked on the correct target. This is accomplished by inserting receive invocations within a message. For example, the dashed path in Figure 9 indicates a 9

System Services

deliver(receive(recEncrypt...)) transmit(recEncrypt...)

deliver(receive(receive(receive(foo...)))) ...

transmit(foo...)

deliver(recEncrypt...) deliver(receive(receive(foo...)))

... EncryptRole

transmit(foo...)

B.recEncrypt...

deliver(receive(foo...)) EncryptRole

...

B.foo...

deliver(foo...)

Proc Msg

Proc Msg

A

B

Figure 9. Multiple roles and contexts are composed by incorporating their behaviors, in order, into the actor state machine. Messages are transformed on delivery so that the correct method is invoked on the appropriate target.

therefore dynamic: by creating new liaisons to handle new connections, the interfaces may change in response to run-time constraints. While components describe an architecture at a functional level, we view connectors as lower level abstractions which de ne how an architecture is deployed in a particular execution environment. By accessing an open implementation of the interface between actors and the underlying system services, connectors implement transparent customizations of component actor behavior. We factor customizations into two categories: roles are explicit customizations of liaisons, while contexts are implicit customizations of all actors within a component. Roles allow the enforcement of interaction policies over connections between components. Contexts support component-wide resource management and coordination. Composition allows multiple connectors to be applied to a single component. In order to test our approach, we are currently in the process of completing a prototype implementation which compiles dcl speci cations into executable systems. Our prototype outputs a system of actors based on a literal interpretation of a dcl speci cation. However, because actors may be used to model a large class of computational objects, dcl speci cations are easily mapped to other targets such as large grain C++ objects with appropriate system support. We use a Javabased actor system and associated meta-architecture as the supporting run-time environment for our prototype. We are also in the process of extending actor semantics to accommodate component-like encapsulation, and a model of resource management and cus-

protocol Encrypt f role EncryptRole f Encrypt role speci cation g

operation installEncrypt(actor end1, apply f EncryptRole to end1; EncryptRole to end2; g

g

end2) f

g

Figure 10. A protocol which uses the EncryptRole specification. This protocol is installed on each participant that requires encrypted interactions.

the context requests the next machine to install on from the manager. The installLoadBalance operation performs the installation.

5. Conclusion Modeling components as hierarchical collections of actors provides a exible mechanism for specifying concurrent and distributed computation; part of the exibility results from the fact that remote communication respects the encapsulation and asynchrony of components. The interface of a component is represented by the behavior of liaisons. Component interfaces are 10

References

protocol GlobalLoadBalance f string machineNames[] = f a list of machines g; int nextMachine = 0; int numMachines = machineNames.length; context RoundRobinBalance() f actorclass nextType; method create(actorclass type, string mach) f nextType = type; g

mgr.requestMachine(self);

method rcvMachine(string newMach) f newAddress(create(nextType, newMach)); g

g

operation installLoadBalance(module mod) f apply f RoundRobinBalance() to mod; g

g

operation requestMachine(actor reqContext) f

g

g

reqContext. rcvMachine(machineNames[nextMachine]); nextMachine = (nextMachine + 1) % numMachines;

Figure 11. A protocol which implements a simple global load balancing strategy.

tomization as described above. The new prototype will continue to build on our earlier experience in using meta-architectures for interaction and coordination.

6. Acknowledgments We thank past and present members of the Open Systems Laboratory who aided in this research. Extra gratitude is extended to Daniel Sturman, Wooyoung Kim, and Carlos Varela whose comments were particularly useful in developing this work. The research described has been made possible in part by support from the National Science Foundation (NSF CCR-9619522) and the Air Force Oce of Science Research (AF BASAR 2689 ANTIC). 11

[1] G. Agha. Actors: A Model of Concurrent Computation. MIT Press, 1986. [2] G. Agha, S. Frlund, W. Kim, R. Panwar, A. Patterson, and D. Sturman. Abstraction and modularity mechanisms for concurrent computing. IEEE Parallel and Distributed Technology, May 1993. [3] R. Allen and D. Garlan. Formalizing architectural connection. In International Conference on Software Engineering (ICSE '94), pages 71{80. IEEE Computer Society, 1994. [4] P. C. Clements. A survey of architecture description languages. In Eighth International Workshop on Software Speci cation and Design, Paderborn, Germany, March 1996. [5] S. Frlund. Coordinating Distributed Objects: An Actor-Based Approach to Synchronization. MIT Press, 1996. [6] W. W. Gibbs. Software's chronic crisis. Scienti c American, 271(3):86{95, September 1994. [7] C. Hoare. Communicating sequential processes. Communications of the ACM, 21(8):666{677, August 1978. [8] G. Kiczales. Beyond the black box: Open implementation. IEEE Software, 13(1):8{10, January 1996. [9] D. C. Luckham, J. J. Kenney, L. M. Augustin, J. Vera, D. Bryan, and W. Mann. Speci cation and analysis of system architecture using Rapide. IEEE Transactions on Software Engineering, 21(4):336{355, 1995. Special Issue on Software Architecture. [10] Object Management Group. CORBA services: Common object services speci cation version 2. Technical report, Object Management Group, June 1997. Available at http://www.omg.org/corba. [11] M. Shaw, R. DeLine, D. V. Klein, T. L. Ross, D. M. Young, and G. Zelesnik. Abstractions for software architecture and tools to support them. IEEE Transactions on Software Engineering, April 1995. [12] D. C. Sturman. Modular Speci cation of Interaction Policies in Distributed Computing. PhD thesis, University of Illinois at Urbana-Champaign, May 1996. [13] The Java Team. Rmi speci cation. Available at ftp://ftp.javasoft.com/docs/jdk1.1/rmi-spec.ps.

Suggest Documents