skip to main content
OpenEdge Development: ADM and SmartObjects
Developing Your Application's Business Logic : Running SmartDataObjects in a distributed environment
 
Running SmartDataObjects in a distributed environment
The SmartDataObject supports distributed computing. You can run a SmartDataObject in a distributed environment using either the traditional client/server model or the AppServer model:
*In the client‑server model, the SmartDataObject runs entirely on one machine as a single .r file and is connected to the necessary databases.
*In the AppServer model, the SmartDataObject is split across the network using AppServer technology, as follows:
*A SmartDataObject proxy, also called a client proxy, resides on the client machine. It interfaces with other client‑based procedures and with the complete SmartDataObject on the AppServer machine.
*A complete SmartDataObject resides with the database on the AppServer machine. It interacts with the database and with the SmartDataObject proxy on the client machine.
The complete SmartDataObject and its proxy interface with each other using AppServer technology.
In this model, it is possible to use a complete SmartDataObject rather than a client proxy on the client machine. This configuration occurs when the partition is configured to run remotely and the client is connected to the database at run time. It happens because the decision on whether to use complete SmartDataObject or a client proxy is based on whether the proper databases are connected, a decision that is independent from the decision on whether to run remotely or locally. Since the partition is an instance property of the SmartDataObject, it is possible to determine which partition is to be used and whether or not it is to be executed locally or remotely only after starting up the SmartDataObject or its proxy. The SmartDataObject runs the same way regardless of whether you run the complete version or its proxy, but the complete version includes code that is not executed by the client in a remote configuration.
Regardless of how you will deploy your SmartDataObject, you need to build it only once and maintain a single set of source code. This is because when you build a SmartDataObject, you use conditional preprocessor statements that identify code sections requiring database access and enable compiling the SmartDataObject into two versions:
*A database‑aware version that contains all of the SmartDataObject code. This version can be used either in the traditional client/server model, or in the AppServer model as the AppServer‑resident procedure that accesses the required databases.
*A non-database‑aware version that is compiled with all database‑access sections compiled out of the r-code. This version is suitable only as the client proxy on the client machine in the AppServer model.
Note: You need to compile conditionally into database‑aware and non-database‑aware versions only if your SmartDataObject will run in a distributed environment using the AppServer model. This is because it is the only configuration in which the SmartDataObject is split into database‑aware and non-database‑aware versions.
The sections that follow describe how to set up the master (.w file) for your SmartDataObject so that it will compile conditionally into database‑aware and non‑database‑aware versions, how the AppBuilder modifies the master, and what happens when the SmartDataObject is initialized in an application.
Setting up the SmartDataObject master for conditional compilation
You use the following tools to set up a SmartDataObject master so it will compile into database‑aware and a nondatabase‑aware versions:
*The DB-AWARE procedure setting in the SmartDataObject template. This already is set to YES in the data.w template.
*A toggle box labeled DB-REQUIRED in the Section Editor for code sections. When you edit an internal procedure or function in the Section Editor, the AppBuilder adds a toggle box labeled DB-REQUIRED to the Section Editor for any section that might contain database references. By default, this toggle box is checked (selected). If you know a section has no references to a database, you can uncheck the toggle box.
AppBuilder modifications to the SmartDataObject master
When you generate the master (.w file) for the SmartDataObject that has been set up for conditional compilation into database‑aware and nondatabase‑aware versions, the AppBuilder modifies the master as follows:
1. It checks each code‑block section to see whether its DB-REQUIRED toggle box is checked. If it is, the AppBuilder brackets the code in that section with the following preprocessor names:
 
{&DB-REQUIRED-START}
. . .
{&DB-REQUIRED-END}
These preprocessor names resolve to the following code:
 
&IF {&DB-REQUIRED} &THEN
. . .
&ENDIF
This code excludes the section from the r‑code during the compilation of the client proxy.
If the section’s DB Required toggle box is unchecked, the AppBuilder does not bracket its code with the {&DB-REQUIRED-START} and {&DB-REQUIRED-END} preprocessor names, and the section is included in the r‑code during the compilation.
2. If the preprocessor names for a section are present, the AppBuilder generates the following code to define them before it produces any code block that might require them:
 
/* DB-Required Preprocessor definitions */
&IF DEFINED (DB-REQUIRED) = 0 &THEN
  &GLOBAL-DEFINE DB-REQUIRED TRUE
&ENDIF
&GLOBAL-DEFINE DB-REQUIRED-START &IF {&DB-REQUIRED} &THEN
&GLOBAL-DEFINE DB-REQUIRED-END   &ENDIF
If DB-REQUIRED is not defined when the compiler processes this block of code, all code blocks are included in the compiled r‑code. However, if DB-REQUIRED is defined as false, code blocks bracketed with {&DB-REQUIRED-START} and {&DB-REQUIRED-END} are not included in the compiled r‑code. This is the case when generating a client proxy (a SmartDataObject proxy to be used on a client machine); it means that the proxy is not required to be connected to any database when executed.
You can choose to compile out just a part of an internal procedure or function. To do this, uncheck the DB-REQUIRED toggle box and program the following statements around the section of code to be executed only when a database connection is available:
 
&IF {&DB-REQUIRED} &THEN
. . .
&ENDIF
This technique allows you to execute different versions of the same procedure on the client and the AppServer. You might even code the client version to invoke the AppServer version; for an example, see the installed file %DLC%\src\adcm2\cltorsrver.i (Windows) or $DLC/src/adcm2/cltorsrver.i (UNIX)
3. When it generates the .w file for the SmartDataObject, the AppBuilder also produces a client proxy .w file. The proxy has the same name of the form sdoname_cl.w, where sdoname is the name of the SmartDataObject. For example, a SmartDataObject named dcust.w automatically has a proxy named dcust_cl.w. The proxy contains the following code:
 
/* dcust_cl.w - non-db proxy for dcust.w */
&GLOBAL-DEFINE DB-REQUIRED FALSE
{dcust.w}
This code, when compiled, first sets {&DB-REQUIRED} to FALSE, then creates an r‑code proxy named dcust_cl.r that is identical to its sibling SmartDataObject named dcust.r except all sections marked DB-REQUIRED are removed.
4. The AppBuilder turns on the SmartDataObject’s DBAware attribute. It uses this attribute later, when it generates a SmartContainer that contains the SmartDataObject.
Initializing the SmartDataObject
When the AppBuilder generates a SmartContainer, it produces calls to the constructObject method for each contained SmartObject. This method launches the contained SmartObject by running it persistently. If a contained SmartObject is a database‑aware SmartDataObject, the AppBuilder appends the DB-AWARE keyword to the SmartDataObject’s name, separated by a CHR(3) character. This serves as a flag to the constructObject method in the containing SmartObject to check the connected databases at run time and determine whether to run the complete SmartDataObject or its proxy.
The constructObject method determines whether to run the complete SmartDataObject or its proxy based on whether all necessary databases are currently connected when the SmartDataObject is about to be executed. If they are, constructObject launches the complete SmartDataObject. If any of the required databases are not connected, constructObject runs the client proxy instead. The proxy then makes the proper AppServer connection to the complete SmartDataObject that is its sibling, based on the partition indicated in its instance attributes setting.