Evolutionary Development of Complex Systems using Rapide: Transaction Processing Case Study, Fundamental Comcepts, a.k.a Tools Introduction

by Dr. John J. Kenney and Woo-Sang Park

last revised  5/08/00

Table of Contents

Introduction System Architecture System Architecture Extension
System Architecture Services Extension Adding a Second Resource System Architecture Service Set Extension Resources Component (Sub)Architecture
Variable Number of Resources
Further Modification to Resource and Some Resources Components
Run-time Interaction with Application Program

Introduction

There are several tools to assist programmers who want to develop Rapide models of systems. The tools include: This series of documents present an evolutionary, example-driven introduction to these tools. By evolutionary we mean the examples begin with very simple models and progress through increasingly complex models.

All of the models are taken from Dr. Kenney's Ph.D. dissertation on transaction processing. The first models present fundamental concepts of transaction processing. Successive models present the properties of atomicity, isolation and durability. The models conclude with advanced features of security, distribution and performance.

Background

Transaction processing (TP) involves multiple application programs sharing several resources where the application programs make requests of the resources and receive results back. This is a specialization of a client server architecture, where clients make requests of servers. However, TP system architectures have additional properties that distinguish them from client server system architectures. For example, client server architectures do not traditionally have ``transactions,'' groups of requests (and there associated processing) that behave atomically. However, it is required for TP systems to have atomic transactions.

A exempliary TP system architecture contains a single application program that communicates with a set of resources. A "boxes and arrows" depiction of such an architecture is given in Figure 1.

TP System Architecture

Figure 1: A TP System Architecture.

Figure 1 shows a system consisting of an application program component (at the top) and several (three) resource components (at the bottom). The arrows connecting the components depict that application program may exchange communication with each of the resources, while the resources cannot communicate with each other directly.

We will use the Rapide tools to produce evolutionary prototype models of TP. However, to do so we must first install the tools so that you can use them.

Installing Rapide Tools

  1. Download the appropriate binary file from ftp://pavg.stanford.edu/pub/Rapide-1.0/toolset/. Note:  the files are of the form rapide.type.buildnum.tar.gz, where type is one of:
  2. Generally, the greater the build number num the "better" the release. Also, note there are several bug fixes available in the debug subdirectory.
  3. Find someplace (preferably /usr) with approximately 50MB of free disk space and extract the tar files:
  4. (where file is the name of the file you downloaded). You should either install the distribution in /usr/rapide, make a symbolic link from /usr/rapide to the distribution, or set the environment variable RAPIDEHOME to the installation directory.
  5. Note:  the following instructions assume you have set the RAPIDEHOME environment variable to the installation directory. If you haven't, then either replace the "$RAPIDEHOME" to the installation_directory/rapide in the rest of this file or (recommended) set RAPIDEHOME to installation_directory/rapide.
  6. Modify your PATH environment variable to include the rapide "bin" directory:
  7. Optionally, modify your MANPATH environment variable to include the rapide "man" directory:
  8. Additionally, the installation and execution of the Rapide toolset require two environment variable to be properly set. Your path must include a directory that contains the `make' program, and your shared library search path must include a directory that contains the xview library libxview.so.3.
  9. Lastly, the Rapide predefined library must be recompiled and a few C++ libraries must be freshened.  Please execute the program:
  10. If you have any problems, please refer to the Rapide FAQ at:

Environment Variables

As discussed in the previous section, the Rapide tools generally assumes the Rapide distribution is installed under the /usr/rapide directory and that /usr/rapide/bin is included in your path. If you installed the installation in another location, you should set the environment variable RAPIDEHOME to that location and include $RAPIDEHOME/bin in your PATH environment variable. Also, you should appropriately set MANPATH and LD_LIBRARY_PATH.

System Architecture

Normally, the first step in building a prototype of a system is to develop an architecture. The Rapide toolsuite provides several ways to do build system architectures, and perhaps the best first step is to use the tool raparch.

Raparch -- The Rapide Architecture Editor

Raparch is a tool for editing Rapide architectures graphically. Boxes and lines may be drawn and edited which corresponds to modules and connections in the architecture of a Rapide program.

Run the raparch program by typing:

% raparch &
A box will appear with several menus at the top, two sets of tool bars on the left, and a grid (called a canvas) in the center. Canvas is equipped with a horizontal and a vertical rulers for convenient positioning of objects. The architecture name is specified in the entry widget (labelled "Arch Name:") at the bottom. There are two sets of tool bars on the lefthand side of a canvas. The first group is for drawing and editing components and connections, such as (create a component) or (create a connection) mode. The second group of tool bars is used to depict features of a component for its behavior specifications. A tool bar in this group can only be activated in conjuction with (select) mode of the first tool bar group.
 
 

Figure 2: Initial View of Raparch

System Architecture (Picture)

The next step is to decide on an intial system architecture for your model. In this example we use a single application program connected to a single resource. This architecture is depicted in Figure 3, and we will now use raparch to construct a model of this architecture.

Single Application Program and Resource System Architecture

Figure 3: Single Application Program and Resource System Architecture.

Create an Application Program Component

To create an application program component, first enter the "create rectangular modules" mode by clicking on thebox icon in the first tool bar group. Then create a box towards the top of the canvas for the application program by positioning the cursor towards the top of the canvas where you want the top left hand corner of the box to be. Then press down, drag and then release left mouse button (or LeftButton) where you want the bottom right hand corner of the box to be. You will see a box labelled "Module 1" appear.

Modify the module properties of application program component by (1) being in box mode, and (2) pressing down in the "Module 1" box on <Alt>-RightButton. An associated module properties window will appear. Modify the "Module Name" to be "APPLICATION_PROGRAM" and modify the "Module Label" to be "Application\nProgram." (The "\n" in the label means a newline) Then click on the OK button.
 

Create a Resource Component

Similarly, create another component at the bottom of the canvas for the resource by: (1) being in box mode, and (2) press down, drag and release the LeftButton from the top left hand corner to the bottom right hand corner.

Modify the modules properties of the resource component by (1) being in box mode, and (2) pressing down in the "Module 2" box on <Alt>-RightButton. Modify the "Module Name" to be "RESOURCE" and modify the "Module Label" to be "Resource." Optionally, you may change the color of the module by typing in a color or using the "Choose..." button to select a color. Finally, click on OK.

Create a Path between the Components

To create a path between the application program and resource components, first enter the "connect modules" mode by clicking on the button in tool bar with the up arrow step icon. Press and release the <Shift>-LeftButton on the application program component and then again on the resource component. This will produce a double headed arrow between the components.

A double headed arrow creates a ``two-way'' connection between the components; by two-way we mean that in the animation that you will produce later in the this tutorial, events will traverse in both directions along this pathway. If you desire a ``one-way'' connection, which limits events to tranverse along the pathway in only the direction of the arrow, then press and release the LeftButton on the source component and <Shift>-LeftButton on the sink component.

Note: A pathway without either arrow heads defaults to one-way in the direction the pathway was created. The direction of the arrow can be changed using a path properties dialogue box.

Modify the connection's path properties by pressing and releasing <Alt>-RightButton anywhere along the path while you are in theup arrow step mode. For example, change the "Path Width" to 3. Finally, click on OK.

Optionally, you can modify the direction of arrow and connection mode by clicking the appropriate radio button for the corresponding field. Like in a component properties window, you may change the color of the path by typing in a color or using the "Choose..." button to select a color. A path name can optinally be specified by typing in a particular name for the path as well.

Resizing and Repositioning

Optionally, you can move a component when you are in the "Selection tool" mode by pressing down on theup arrow icon, pressing down and dragging the component with LeftButton. Notice that when a component is selected it turns blue.

Optionally, you can resize a component when you are inbox mode by pressing down and dragging an edge of the box with <Shift>-RightButton.

Optionally, you can reposition a path when you are inup arrow step mode by pressing down and dragging an end of the path with <Shift>-RightButton.

Saving the Architecture

The architecture picture that we have built can be saved two ways. First, saved to a Rapide source file that can be compiled and executed (saved in a file with ".rpd" extension by default). Second, saved to an architecture file that can be used to animate the results of an execution (saved in a file with ".arch" extension by default).To perform the latter, select the Save option of the File menu. This creates a file named "main.arch" that contains a description of the architecture in a format that is understood by raparch and raptor. You can save the description in file with another name by using the Save As option of the File menu.

Note: If you save the file under a different name, be sure to use that name instead of main.arch throughout the rest of the example! So far we are building a conceptual (initial) model of the system architecture. We save this conceptual architecture in "main_concept.arch" by the Save As option of the File menu. The file name is inherited from the name used in "Arch Name" field at the bottom of the canvas. A default architecture name used is "main".

System Behavior

Rapide (and raparch) allows us to associate prototypical behaviors to our system. We can provide the architecture with sementics, in other words, we are constructing a structural and behavioral model of the system architecture.

Application Program Behavior

To associate a behavior with the application program component, first we create required features for the component: (1) being in mode in the first tool bar group, (2) clicking on the icon in the second tool bar group. Then create an out action feature over the boundary of application program component by <Control>-MiddleButton (middle mouse button on 3-button mouse or both left and right mouse button pressed simultaneously on 2-button mouse).
Modify the properties of out action feature of application program component by (1) being in mode ,  (2) being in mode , and (3) pressing down in the "out action" feature on <Alt>-RightButton. Modify the "Name" to be "Request". Similarily we create the other in action feature for application program component and name it to be "Result". Now, the structural interface of application program component is established and the next step is to specify a behavior for application program component based on its constituting in and out action features.
To describe a behavior for the application program component, you must be inbox mode and press <Control>-RightButton on the application program component. This brings up a window that defines the Rapide interface type associated with the application program component. At this point, raparch should provide the structural interface constituents in "acitons and  services" section of the type interface window properly. (note: sometimes pressing <Control>-RightButton over components causes the architecture description window open. This is a minor raparch bug to be fixed in the next release. If that happens, ignore the architecture window by clicking the Cancel Button in the window.) Make sure that actions and serives section contains:
action out  Request();
action in   Result();
These action declarations mean that the application program can generate "out" Request events and receive "in" Result events. These actions will be "visible" to the resource component as we shall see later.

Click on the "Behavior..." button to describe the component's behavior rules. It will bring up a new window for the component behavior, labelled "APPLICATION_PROGRAM." There are "Behavioral Declarations" and "Behavioral Rules" sections in the new window. Interfaces in Rapide can also include behavioral declarations that we will initially leave alone. We will modify them later to enrich our behavioral specification. Notice the default action declaration that is special. This action's associated events communicate to raptor the "name" of the component that generated the event.

Modify the behavioral rules section to be:

start =>
  animation_Iam("APPLICATION_PROGRAM")
   -> Request();;
This behavior rule waits until a start event is observed and reacts to it by generating two events: an animation_Iam event and a Request event. The animation_Iam event is parameterized with the string "APPLICATION_PROGRAM."

When you are finished making the modifications, click on the DONE button for behavioral rules window and OK button for type interface window. The snapshot of this architecting process is depicted in Figure 4.
 
 

Figure 4: Application Program Component Features and its Behavioral Descriptions.

Resource Behavior

Similarily now we will associate a behavior with the resource component. First, we create required features for the resource component, as explained in the above: (1) being in mode , (2) clicking on the icon , then create an out action ("Result") and an in action ("Request"). The structural interface of resource component should be properly collected by raparch and be shown in type interface window. Associated behavior can be specified in the same way as we described for the applicaiton program component. Make sure that resource componet contains:
action  in  Request();
action  out Result();
And modify the "behavioral rules" section in a behavior window to be:
start => animation_Iam("RESOURCE");;
Request() => Result();;
When you are finished making the modifications, click on the DONE button for behavioral rules window and OK button for type interface window. The snapshot for RESOURCE component behavior modification can be shown in a similar figure like Figure 4.
 

Create Pathes between the Features of Components


Modify connections for the system. First, delete a connection made between application program and resource components by selecting the path between two components and using Delete option of the Edit menu. Instead we will make a connection between two components, in terms of components' features, that is, "Request" and "Result" action pair of each component. To create a path between features of components, first  enter the "connect modules" mode by clicking on the button in the first tool bar group with icon. Press and release LeftButton on the out action "Request of Application Program" and then again on the in action "Result of Resource" component.. This will produce a solid line between two features. Modify the connection's path properties by pressing and releasing <Alt>-RightButton anywhere along the path while you are in the  mode. For example, modify the "Path Width" to 3 and connection mode to be "pipe" for now, then click on the OK button. You will see a change of line pattern for a path, from a solid line to a dotted line. Details about connections will be discussed later in this tutorial. Note: Since features of components already implies the direction of flow (e.g., out or in), arrows may not be required for connections between features. A solid line represents a basic connection and a dotted line for a pipe connection in Rapide. Figure 5 shows two pipe connections between Request and Result action pairs of ApplicationProgram and Resource components in the architecture.
 
 

Figure 5:  Connections between Components based on their Features.

Main Architecture

Now we will associate code with the "main" architecture. In eitherbox or up arrow mode and press <Control>-RightButton on an empty portion of the canvas to bring up the Rapide architecture description window. Once agiain raparch should be able to collect constituting components and connections automatically. Make sure that main architecture window contains the following declarations in "Decalarations in architecture" section. Note: Current raparch implementation may need a bit of massages for Rapide source code generation in some cases. "Declarations in architecture" section shows APPLICATION_PROGRAM and RESOURCE declarations separated by ":". Names prior to ":" represent components' identifiers in the architecture, and following APPLICATION_PROGRAM and RESOURCE represents Rapide interface types.
APPLICATION_PROGRAM : APPLICATION_PROGRAM;
RESOURCE  : RESOURCE;
And make sure "Architectural Connections" section to be:
connect
   APPLICATION_PROGRAM.Request() => RESOURCE.Request();
   RESOURCE.Result() => APPLICATION_PROGRAM.Result();
When you are finished making the modifications, if needed, and click on the OK button. The situation is depicted in Figure 6.
 
 

Figure 6: Main Architecture Description

Generating the Rapide code


The architecture code that you have specified can be used to generate a Rapide program via the Generate Rapide Code option of the RAPIDE menu. Enter "main.rpd" in the selection widget to create a file named main.rpd.

When you are finished making the selection, click on the OK button. You will have produced a file named main.rpd containing the following Rapide program.

TYPE APPLICATION_PROGRAM IS INTERFACE
    action out  Request();
    action in   Result();
  BEHAVIOR
    action animation_Iam(name: string);
  BEGIN
    start => animation_Iam("APPLICATION_PROGRAM") -> Request();;
END;

TYPE RESOURCE IS INTERFACE
    action in  Request();
    action out Result();
  BEHAVIOR
    action animation_Iam(name: string);
  BEGIN
    start => animation_Iam("RESOURCE");;
    Request() => Result();;
END;

ARCHITECTURE MAIN() IS
    APPLICATION_PROGRAM : APPLICATION_PROGRAM;
    RESOURCE  : RESOURCE;
  CONNECT
    APPLICATION_PROGRAM.Request() => RESOURCE.Request();
    RESOURCE.Result() => APPLICATION_PROGRAM.Result();
END;
Also, save raparch's state with the Save option of the File menu. This completes the construction of the structural and behavioral model, in two files named "main.arch" and "main.rpd."

System Execution

The code saved in main.rpd can be compiled, executed and analyzed.

R.manager -- The Rapide Library Manager

To compile a Rapide program, a Rapide library must first be built. A Rapide library store information about the predefined and user defined types and modules. To create a library, type:
% r.mklib

Rpdc -- The Rapide Compiler

To compile the code in main.rpd to create an executable type:
% rpdc -M main -o main main.rpd
Compiling the program should take approximately 1 minute on a Sun Ultra. If you get errors during the compilation, please check the associated sections of the code for typographical errors. Upon correcting the error, don't forget to save the program.

Execute the program by typing:

% main
This will produce a history of the execution recorded in main.log.

System Analysis

There are several forms of analysis provided by the Rapide toolsuite. In particular, we will use raptor and pov.

Raptor -- The Rapide Animator

To create a graphical animation of what happened during the execution, type:
% raptor -a main.arch main.log &

Pov -- The Rapide Partial Order (poset) Viewer

We can visualize what happened during the execution another way using the pov. The pov can create several views of the events that were generated during the execution. In particular, a directed acyclic graph can be generated whose arrows denote the causal (or more accurately the dependency) relationship between the events. If an arrow goes from an event A to another event B then event B depends on event A.

The pov is invoked with the log file name as its command line argument:

% pov main.log &
The pov starts initially with the view manager window which lists the computations (and views) that have been loaded; at this point only one computation has been loaded, the main.log, and it has been given the label "Computation 1." To examine the poset graphically, select Computation 1 and use the poset viewer option of the View menu. Also, try the table viewer to represent the events in a tabular form.

main.log

Figure 6: Pov's PlanarViewer of main Execution.

If you are running a secure X server, you can coordinate the animation's displaying of the events with modification of the pov's poset viewer's coloring of the events. To coordinate the animation with the visualization, you may drag and drop the computation from the pov to raptor. One way to do this is to click and hold RightButton on "Computation 1" in the view manager window of the pov and drag the computation over to the raptor window. When the dragged computation turns green, you may release the button. If the computation doesn't turn green, you are probably not running a secure X server.

System Architecture Extension

Now, let's enrich the application program's behavior to make several requests of the resource instead of just one. This can be done by modifying the application program Rapide behavior. Inbox mode press the <Control>-RightButton on the application program component.

Modify the behavioral declarations section to include:

i : var Integer := 0;
Also add the following rule to the behavioral rules section:
Result() =>
  if ( $i < 4 ) then
    i := $i + 1;
    Request();
  end if;;
Save raparch's state with the Save As option of the File menu and generate the Rapide code (via Generate Rapide Code option of RAPIDE menu) under the name main2.arch and main2.rpd respectively.

To compile this version, we must remove the references to the APPLICATION_PROGRAM and RESOURCE modules in the library manager's database. To do so, clean the library or remove the main.rpd.

% r.rm main.rpd
or
% r.cleanlib
and to compile it:
% rpdc -M main -o main2 main2.rpd
After execution we can analyze the execution via raptor and pov.
% main2
% raptor -a main2.arch main2.log &
% pov main2.log &
TP System Architecture

Figure 7: Pov's PlanarViewer of main2 Execution.

System Architecture Services Extension

Next, we will enrich the architecture to make use of services. The first step in this process is to create the interface (or service) that will be shared by the application program and resource.

Application Program and Resource Service

The Application Program and the Resource interfaces really use opposite sides of a common interface, which we will call the AP_R interface. This interface denotes the kinds of interaction that can occur between these two components. In general the interaction can be described in Rapide via functions or actions. Actions are more general than functions, since functions impose additional synchronization between the caller and the callee; the caller must wait after making the function call until the callee returns before proceeding. Actions are asynchronous, and the caller is free to continue doing other activities and react to the results at his leisure. We have chosen to represent the interaction with actions.

We will modify the (main2) system to demonstrate how to use service features. We can construct AP_R interface in two ways: (i) create the interface graphically, specify properties of component with constituent features (in the same way we constructed the other components in the architecture), and then delete the graphical AP_R object from the canvas - in effect only the component's type interface kept, or (ii) create the interface textually using the Show Type Interfaces option of the RAPIDE menu. We introduce the latter method: select the Show Type Interfaces option of the RAPIDE menu. Press on the NEW button of the shwif window. Name the interface "AP_R" and add the followings to the actions and services section:

action
  out  Request();
  in   Result();
Modify the behavior rules section to be:
start => animation_Iam("AP_R");;
When you are finished making the modifications, click on the DONE button and the OK button in order.

Notice that the AP_R entry is at the bottom of the Rapide Type Interfaces section of the shwif window. This is a minor problem, because we will be using the AP_R definition in our modifications of the APPLICATION_PROGRAM and RESOURCE type interfaces, and a type can only be used after it is declared. Therefore, we will need to reorder the list of interface types. This is accomplished by dragging the AP_R entry above the APPLICATION_PROGRAM entry with the RightButton. Click on Done.

Adding a Service to the Application Program Interface

Modify features of components and pathes in the (main2) architecture. First, delete features of components (application program and resource) and pathes among them and make sure that we have constructed AP_R service type interface as explained in the above: (1) being in mode, (2) press <Shift>-LeftButton on features and pathes of application program and resource components to select objects on the canvas. Then delete selected objects by the Delete option of the Edit menu. We are about to introduce AP_R service features in the architecture: (1) being in mode, (2) clicking on the mode, and create a normal service over the boundary of application program component by <Control>-MiddleButton. Modify the properties of the service in the same way we modified those of action features of components in the previous section and press the OK Button: name to be "R" and type to be "AP_R". In box mode, press the <Control>-RightButton on the application program component in the canvas. Raparch should provide the actions and services section with the following declaration:
    service R : AP_R;
And modify the behavioral rules section to look like:
start =>
  animation_Iam("APPLICATION_PROGRAM")
   -> R.Request();;

R.Result() =>
  if ( $i < 4 ) then
    i := $i + 1;
    R.Request();
  end if;;
Click on the DONE and the OK Buttons in order for APPLICATION_PROGRAM type interface window.
 

Adding a Service to the Resource Interface

We introduce another way to modify behavior for the resource component textually using "MODIFY" option in the "Show Type Interface" option of the RAPIDE menu. After we add a dual service feature onto resource component graphically, select a type interface, RESOURCE, and click on the MODIFY button in shwif window brought up via the Show Type Interface option of RAPIDE menu. It opens up the RESOURCE type interface window. And make the following modifications to its actions and services and its behavioral rules sections:
service AP : dual AP_R;

start => animation_Iam("RESOURCE");;
AP.Request() => AP.Result();;
Now, we need to make a connection between two services of application program and resource components in the same way explained in the previous architecture (main.arch). And modify connection's properties by pressing <Alt>-RightButton anywhere along the path in mode: Path Width to be 3, connection mode to be pipe.

Modifications to Main to reflect Services

Finally, we associate code with the main architecture. Open up the Rapide architecture description window by pressing <Control>-RightButton on an empty portion of the canvas while in either or mode. Once again raparch should be able to provide contituent components and connections automatically. Make sure that main architecture window shows the following in the architectural connection section:
 
connect
    APPLICATION_PROGRAM.R  =>  RESOURCE.AP;


Click on OK. The architecture with services extension is demonstrated by Raparch  in Figure 8.
 
 

Figure 8:  Main Architecture Description with Services Extension (main3.arch)




Analysis of Architectures with Services
Save state with the Save As option of the File menu and generate the Rapide code with the latest modifications under the name main3.arch and main3.rpd. Then, compile and execute main3 via:

% r.cleanlib
% rpdc -M main -o main3 main3.rpd
% main3
% raptor -a main3.arch main3.log &
% pov main3.log &

Adding a Second Resource

The next upgrade we will make to our prototype is add a second resource to our architecture.

Adding Service for Second Resource to the Application Program Interface

Resize the application program component for another service feature for the second resource component. Create another normal service feature with <Control>-MiddleButton while in and mode. Modify the properties of a service feature in property window:  Name to be "R2" and type to be "AP_R. When you open up a type interface window for application program component with <Control>-RightButton, actions and services section of the type interface window should reflect changes in the component properly.
service
  R  : AP_R;
  R2 : AP_R;
And add the following declaration to the behavioral declarations section:
action generate_requests();
And modify the behavioral rules section to look like:
start =>
  animation_Iam("APPLICATION_PROGRAM")
   -> generate_requests();

R.Result() ~ R2.Result() =>
  if ( $i < 4 ) then
    i := $i + 1; 
    generate_requests();
  end if;;

generate_requests() =>
  ( R.Request() || R2.Request() );;
When you finish modifications, click on DONE and OK buttons.

Second Resource Component

Resize the existing resource component to make a room for the second resource component: while in mode, press down and drag an bottom right hand corner of resource component box with <Shift>-RightButon, and release the button at the desired position. Create duplicate resource component at the bottom of the canvas for the second resource by selecting the resource component and selecting the Duplicate option of the Edit menu. Modify the modules properties of the resource component: 1) module name to be "RESOURCE2" and 2) module label to be "Resource2."

Position the second resource component where you want the box to be. Then, create a dual AP_R service feature on the second resource box: Name the service to be "R2" and the type to be "AP_R" in the feature property window. Open up the RESOURCE2 type interface window. The type interface window should contain the following declaration in the actions and services section:

    service AP : dual AP_R;
And make the following modifications in its behavioral rules sections:
 
    start => animation_Iam("RESOURCE2");;
    AP.Request () => AP.Result ();;
Note: Due to the limitation in the current raparch implementation, when you duplicate an component, features of a component are not duplicated, thus you must create constituent features manually. You can move components around on the canvas by selecting and dragging them with LeftButton while in mode. Also you may want to turn off "snap" option in Options menu for more precise positioning of objects on the canvas.

Create a pair of connections between application program component and two resource components (Resource and Resource2): one path between "R of Application Program" and "AP of Resource" and the other between "R2 of Application Program" and "AP of Resource2".

Modifications to Main to reflect Second Resource

Finally, we associate code with modified main architecture. Raparch should be able to reflect the changes in the architecture description window. Conform that the architecture window contains the following piece of code and make adjustments, if needed. Again, inbox or up arrow mode, press <Control>-RightButton on an empty portion of the canvas. In the architectural declarations section, there should be three declarations:
APPLICATION_PROGRAM : APPLICATION_PROGRAM;
RESOURCE  : RESOURCE;
RESOURCE2 : RESOURCE2;
And make sure that the architectural connections section to be:
APPLICATION_PROGRAM.R => RESOURCE.AP;
APPLICATION_PROGRAM.R2 => RESOURCE2.AP;
The architecture with a second Resource component is demontrated by Raparch in Figure 9.
 
 

Figure 9:  Main Architecture with a Second Resource Component (main4.arch)


Analysis of Architectures with Second Resource

Save state with the Save As option of the File menu and generate the Rapide code with the latest modifications under the name main4.arch and main4.rpd. Then, compile and execute main4 via:
% r.cleanlib
% rpdc -M main -o main4 main4.rpd
% main4
% raptor -a main4.arch main4.log &
% pov main4.log &

System Architecture Service Set Extension

We will extend the (main3) system to use sets (or more precisely lists) of services. Reopen the main3.arch file by selecting the Open option of the File menu. Select main3.arch and click on OK.

AP_R Service Modification

The AP_R service must be modified to work around an implementation deficiency in the current Rapide compiler's ability to match certain kinds of patterns. The "bug" occurs when the compiler attempts to match patterns of the form:
(?Idx : Integer) Service_Set(?Idx).Action_Name()
The work-around is to use a parameter of the event to record the index. Thus, instead of writing the previous pattern we will write:
(?Idx : Integer) Service_Set(?Idx).Action_Name(?Idx)
Therefore, we will modify the actions of the AP_R service interface to include a parameter that will record the appropriate service set index value. Select the Show Type Interfaces option of the RAPIDE menu. Modify the AP_R interface to be:
action
  out  Request(index : Integer);
  in   Result(index : Integer);

Application Program Component

First, we modify application program component by replacing service features by set of services. Select both normal and dual services of components with <Shift>-LeftButton in mode and delete them with Delete option of Edit menu. Note: the connection between two services will be dropped automatically by Raparch. Then, create a normal service set for the application program component with <Control>-MiddleButton, while in andmodes. Modify the properties of the service set with <Alt>-RightButton: Name to be "Rs", Parameter to be (1..2), and type to be "AP_R".

Actions and Services

The application program will now contain a set of services for connecting to the a set of resources.
service Rs(1..2) : AP_R;

Behavioral Declarations

And add the following declaration to the behavioral declarations section:
action generate_requests();

Behavioral Rules

start =>
  animation_Iam("APPLICATION_PROGRAM")
   -> generate_requests();;

generate_requests() =>
  [ !i in 1..2 rel || ] Rs(!i).Request(!i);;

[ !i in 1..2 rel ~ ] Rs(!i).Result(!i) =>
  if ( $i < 4 ) then
    i := $i + 1; 
    generate_requests();
  end if;;

Resources Component

Modify the Resource component of the main architecture to be named "RESOURCES" and labelled "Resources." And similarly we create a dual service set for the resources component with <Control>-MiddleButton in and modes. Modify the properties of the service set
with <Alt>-RightButton: Name to be "AP", Parameter to be "(1..2)", and type to be "AP_R". Resources component will now contain a set of services for connecting to the application program component. Verify that resources type interface contains the actions and services section to be:
service AP(1..2) : dual AP_R;
Modify the behavior section to be:
start =>
  animation_Iam("RESOURCES");;

(?i : Integer) AP(?i).Request(?i) =>
  AP(?i).Result(?i);;
And make a connection between service set of application program and resources components and modify the properties: Path width to be 3, Connection mode to be pipe.

Main Architecture

Verify that the architecture description window contains:
APPLICATION_PROGRAM : APPLICATION_PROGRAM;
RESOURCES : RESOURCES;
APPLICATION_PROGRAM.Rs => RESOURCES.AP;
The architecture with service set extension is demonstrated by Raparch in Figure 10.
 
 

Figure 10:  Main Architecture Description with Service Set Extension (main5.arch)


Analysis of main5

Save state with the Save As option of the File menu and generate the Rapide code with the latest modifications under the name main5.arch and main5.rpd. Then, compile and execute main5 via:
% r.cleanlib
% rpdc -M main -o main5 main5.rpd
% main5
% raptor -a main5.arch main5.log &
% pov main5.log &

Resources Component (Sub)Architecture

Now we will give the resources component an (sub)architecture for its implementation.

Modify the modules properties of the resources component: 1) module name to be "SOME_RESOURCES" and 2) module label to be "Some\nResources."
 

Some Resources Subarchitecture

In up arrow mode, double click on the Some Resources component to bring up subarchitecture. Draw two components, one named "RESOURCE" and labelled "Resource" and the other named "RESOURCE2" and labelled "Resource2."  Create a dual AP_R service for each resource component: both services are named as "AP" and typed with "AP_R". Add paths from the service of components to the top boundary of the canvas: once again path width to be 3 and connection type to be pipe. Note: The presence of a subarchitecture is represented by a thick outline around the component objects (when a new subarchitecture canvas is open, a think outline must be drawn around the component automatically and at the same time background color of subarchitecture canvas will be the same as the color of the parent component). Constituent features of a parent component (in this case Some_Resources component) must be depicted automatically around boundary of subarchitecture canvas. However, due to the implementation deficiency in the current Raparch capability to depict features on the canvas, any location of the canvas boundary is represented as features for the parent component.  Note that in Figure 11, dual service set feature on the subarchitecture canvas is created manually for clarity of the graphical representation of a feature. In the current Raparch implementation, boundary of a subarchitecture canvas serves as feature template for the parent component.

Resource Components in subarchitecture SOME_RESOURCES

Modify the behavior associated with the RESOURCE component (by being in mode and pressing <Control>-RightButton). The behavior rules should be:
 
    start => animation_Iam("RESOURCE");;
    (?i: integer) AP.Request(?i) => AP.Result(?i);;
Now add a similar behavior to the RESOURCE2 component. A trick to efficiently copying the RESOURCE's behavior over to the RESOURCE2 component is to bring up the type interface window for the RESOURCE2 component, change the name to be RESOURCE, and then press Enter. This will bring over the RESOURCE behavior. Modify the name back to RESOURCE2. Dont' worry about the name in the animation_Iam event. Raparch will automatically update the name to be the name of the interface type.

Resources Subarchitecture

Modify the architecture description for Some Resources. Don't forget that you modify the architecture description by being in box orup arrow mode and pressing <Control>-RightButton on the Some Resources subarchitecture canvas. The modications are: Close the Some Resources subarchitecture.
 

Main Architecture


Finally, verify that main architecture contains the following in architectural declarations and connectictions sections:
 

APPLICATION_PROGRAM : APPLICATION_PROGRAM;
SOME_RS : RESOURCES is SOME_RESOURCES();
connect
    APPLICATION_PROGRAM.Rs => SOME_RS.AP;

 

 

The architecture with a subarchitecture is demontrated by Raparch in Figure 11.
 
 

Figure 11:  Main Architecture Description with a subarchitecture (main6.arch)

Analysis of Main6

Save state with the Save As option of the File menu and generate the Rapide code with the latest modifications under the name main6.arch and main6.rpd. Then, compile and execute main6 via:
% r.cleanlib
% rpdc -M main -o main6 main6.rpd
% main6
% raptor -a main6.arch main6.log &
% pov main6.log &
When you animate main6, you can examine the subarchitecture by double-clicking on the Resources component. Another window will appear that contains the Resources subarchitecture.

Variable Number of Resources

All of the previous examples assumed the system had only one or two resources. This section will prototype a family of systems (or style) where the number of resources varies. In particular, the number of resources will be defined by a command line parameter when the associated executable is run.

Modification to Application Program

Since the number of resources will vary, the number of AP_R "services" the application will use must be appropriately modified. We modify the APPLICATION_PROGRAM from being an interface type to an interface type constructor containing a formal parameter that declares the number of resource services. Modify the type interface associated with the APPLICATION_PROGRAM component.

Modify the formal parameters to be:

(n : Integer)
and the actions & services from:
service Rs(1..2) : AP_R;
to
service Rs(1..n) : AP_R;
and the behavioral rules from:
[!i in 1..2 rel ~] Rs(!i).Result(!i) =>

[!i in 1..2 rel || ] Rs(!i).Request(!i);;
to
[!i in 1..n rel ~] Rs(!i).Result(!i) =>

[!i in 1..n rel || ] Rs(!i).Request(!i);;
Note: Currently, a bug in the modification function causes the old application program interface to persist, despite being modified to include the formal parameter. Please remove it from the type interfaces list. (NOT any longer !)

Modification to Some Resources Component

Similarly, modify the interface associated with the Some Resources component:

Formal parameters:

(n : Integer)
and the behavioral rules from:
service AP(1..2) : dual AP_R;
to
service AP(1..n) : dual AP_R;
Don't forget to remove the old RESOURCES type interface.

Modification to Some Resources Subarchitecture

In up arrow mode, double click on the Some Resources component of the main architecture to bring up the SOME_RESOURCES subarchitecture. Then box orup arrow mode and press <Control>-RightButton to bring up the architecture description for SOME_RESOURCES.

Modify the formal parameters of the architecture constructor to be:

(n : Integer)
Modify the Return Type Interface to be:
 RESOURCES(n)
Modify the Declarations in architecture to be:
action animation_Iam(name: string);
Rs : array[Integer] of RESOURCE
       is (1..n, default is new(RESOURCE));
Modify the Architectural Connections to be:
connect
  for i : Integer in 1..n generate
    AP(i) => Rs[i].AP;
  end generate;
initial
  animation_Iam("SOME_RESOURCES");
Note: Experiment by using different connections here. In particular, look at the poset produced using "to" and "||>". Details of connections may be found in the Architecture LRM, but we will give a brief overview of Rapide connections:

A connection consists of an optional sequence of outermost placeholder declarations, a trigger to the left of an operator, an operator (to, => or ||>) and a body to the right of the operator. The scope of the outermost placeholder declarations extends to the end of the rule.

A connection rule with the to operator is called a basic connection.

A connection rule with the => operator is called a pipe connection.

A connection rule with the ||> operator is called an agent connection.

A connection rule between service names is called a service connection.

In general, connections execute by searching for matches to its trigger. Upon finding a match and associated binding of outermost placeholders, the body of the connection will be generated. The relationships among the events of the body, the triggering events, and other events generated by the connection are dependent upon whether the connection is basic, pipe or agent.

Basic Connections

The generated event is causally and temporally equivalent to the triggering event.

Pipe Connections

The generated event(s) are all causally dependent upon all triggering events, and upon all events generated by previous executions of the connection.

Agent Connections

The generated event(s) are all causally dependent upon all triggering events, but they are (otherwise) causally unrelated to the events generated by previous executions of the connection.

Service Connections

A (basic|pipe|agent) service connection between dual services, say S and R, results in a set of (basic|pipe|agent) connections, one for each pair of constituents with the same name in the two services.

Duality is the Rapide way of denoting the gender of the services. To connect two components together through services, the trigger and body of the rule must be service names and the service named in the body must be of the dual type of the type of the service named in the trigger.

A connection between services is usually bi-directional in the sense that constituents from each service will be action names in a trigger of a connection defined by the service connection.

Modification to Main Architecture

Modify the architecture declarations to be:
n  : Integer is Cast( String, Integer, Arguments[1] );
AP : APPLICATION_PROGRAM(n);
Rs : RESOURCES(n) is SOME_RESOURCES(n);
Optionally, modify the architecture connections. Experiment by using different connections here also. In particular, look at the poset produced using "to" and "||>".
 

Analysis of Main7

Save state with the Save As option of the File menu and generate the Rapide code with the latest modifications under the name main7.arch and main7.rpd. Then, compile and execute main7. Don't forget to add a command line parameter to indicate the number of resources. Look at the poset via the pov.

Note: If you use raptor to animate main7, you may notice the events in the subarchitecture don't flow to the "right" resource all of the time. We will correct this in the next section. The architecture with variable number of resources (main7.arch) is graphically equivalent to Figure 11 (i.e., main6.arch; in this case, the maximum number of resources that will be created is "2").

Further Modification to Resource and Some Resources Components

To associate a particular raptor resource component with a specific component in the Rapide code, a little extra code needs to be written. As you may have already guessed, the RESOURCE component must generate an appropriate animation_Iam event with the same string that the architecture picture used to name the component. This means the RESOURCE interface must be given an appropriate "index" at run-time to specify which index it has in the RESOURCES's array of RESOURCEs.

Modification to RESOURCE Interface

We chose to define an "in" action that provides the "index". Modify the actions and services section to include:
action in Init(i : Integer);
Also, modify the behavior replace:
start => animation_Iam("RESOURCE");;
to be:
(?i : Integer) Init(?i) =>
    animation_Iam("RESOURCE" & Cast(Integer, String, ?i));;

Modification to Some Resources Subarchitecture

To make the animation appear to represent the actual number of resources created in the execution, you must first modify the subarchitecture to contain the maximum number of resources that will be created in the execution. Then we modify the architecture file to initially make the components in the animation invisible. Then make only those that are used in the animation visible.

The Number of Components

Modify the SOME_RESOURCES subarchitecture to contain the maximum number of resources. Each added resource's component must have a module name similar to RESOURCEnumber and with type interface RESOURCE.

In particular, you may optionally modify (i) rename Resource component as Resource1, and (ii) the interface type associated with the Resource2 component to be RESOURCE instead of RESOURCE2.

Modification to the Description

Add the following to the connections:
animation_Iam =>
  for i : Integer in 1..n generate
    Rs[i].Init(i)
  end generate;

Modification for main8.arch

Also, modify the main8.arch file so that it includes the following text. Do that by bringing up the Raptor directives via <Control>-LeftButton on the main canvas. Any code written in this file will be prepended to the arch file. Include the following code in the Raptor directives section:
proc per_event { event_idx name parameters caller } {
  if { $event_idx == "0" } {
    rpChangeState SOME_RESOURCES RESOURCE invisible -p
    rpChangeState SOME_RESOURCES RESOURCE2 invisible -p
  }

  if { $name == "INIT" } {
    set id [lindex $parameters 0]
    set module "RESOURCE$id"

    rpChangeState SOME_RESOURCES $module normal -p
  }
}
Note: include as many lines of the following form as the number of resources in your subarchitecture. The lines indicate the particular RESOURCE, a component of the SOME_RESOURCES architecture, should be initially be invisible.
rpChangeState SOME_RESOURCES RESOURCEn invisible -p

Analysis of Main8


Save state and generate the Rapide code with the latest modifications under the name main8.arch and main8.rpd. Then, compile and execute main8. Don't forget to add a command line parameter to indicate the number of resources. Note that the base architecture with dynamically varying number of resources (main8.arch) is graphically equivalent to Figure 11 (i.e., main6.arch).

Run-time Interaction with Application Program

The following code exemplifies a method of allowing the user to interact with the simulation at run-time. Modify the application program's type interface to be:

Actions & Services

service Rs(1..n) : AP_R;
Behavioral Declarations
  action
    animation_Iam(name: string),
    Continue(),
    Parallel_Requests(),
    Single_Request(i : Integer);
  bool : var Boolean; 
  str : var String;
Behavioral Rules
  start => animation_Iam("APPLICATION_PROGRAM");;

  /*
       After a Start or Continue event, decide to quit or generate either
       a single resource request or requests to all resources in parallel.
   */
  Start or Continue =>
    IO.Cput("Which resource to use?  [-1] quit, [0] all in parallel");
    str := IO.Cget();
    bool := Can_Cast(String, Integer, $str);
    while ( not $bool ) do
      IO.Cput($str & " is not an integer, enter an integer.");
      str := IO.Cget();
      bool := Can_Cast(String, Integer, $str);
    end do;
    if ( Cast(String, Integer, $str) = 0 ) then
      Parallel_Requests();
    elsif ( Cast(String, Integer, $str) > 0 ) then
      Single_Request( Cast(String, Integer, $str) );
    end if;;

  /*
       After making the decision generate a single resource request.
   */
  (?i : Integer) Single_Request(?i) ||> Rs(?i).Request(?i);;

  /*
       After making the decision generate a request to each (1 to N) of
       the resources in parallel.
   */
  Parallel_Requests ||>
    [ !i in 1..N rel || ] Rs(!i).Request(!i);;

  /*
       If the AP made a single request and received a result back or if
       the AP made parallel requests and received N results back, then
       continue.
   */
  ((?i : Integer) Single_Request(?i) ~ Rs(?i).Result(?i)) or
    (Parallel_Requests
     ~ [ !i in 1..N rel ~ ] Rs(!i).Result(!i))
  ||>
    Continue();;
The "[ !i in 1..N rel || ] Rs(!i).Request(!i)" in the above code is what we call an iteration pattern. It will generate "n" request events. Each of the request events will be causally independent from the other request events. Note: all of the request events will causally follow the triggering parallel_requests event.

Similarly, the "[ !i in 1..N rel ~ ] Rs(!i).Result(!i))" in the above code is another iteration pattern. In this case, we want to match when we don't care what the relationships between the results events are; the compiler will match even when some of the the results events are causally independent from one another and others are causally dependent.