Setting the Stage for Object REXX Scripting
by Mike Baryla
Hit movies and popular applications have one thing in common they both need great scripting. Unfortunately, users can't just tell your application to "Run it again, Sam" without a little work on your part. You need to make your application scriptable.
Whether for traditional uses or emerging marketplaces, scriptability makes a difference in the success of an application. This article provides an overview of what it takes to make your application scriptable from a REXX procedure.
Success Starts with Scripting
A scriptable application, in the broadest sense, is one that can be controlled or used by some other program. Usually this other program is written in a high-level scripting language, such as REXX. Making your application scriptable often makes it a more desirable application (and increases user demand for it).
One traditional use of scripting is for customizing applications. Users add functions to meet special needs or to increase productivity OS/2's Enhanced Editor is an example of an application that can be customized through scripting. Users customize the editor by writing REXX procedures that they can run as editor macros. Many other editors (such as WordPerfect and Lotus AmiPro) and spreadsheets (such as Lotus 1-2-3) have similar capabilities.
Another use of scripting is to combine several scriptable applications into a single composite application. For example, you can use a composite application to retrieve data from a spreadsheet and then manipulate that data with an editor to generate a file containing a report. Composite applications are powerful tools for creative problem solving. But composite applications can be written only if the applications managing the needed data are scriptable.
Consider, for example, how scripting could help decision makers who rely on information from online sources Often the decision maker must access several sources. Each source has an application with a unique interface, and most are designed with the assumption that a person will operate the interface manually. Unfortunately for decision makers, as the number of sources increases, so does the time and work needed to get the information.
If the applications that retrieved the information were scriptable, a single script could make inquiries to several information sources. The script could then compile and present the information in a format that is meaningful to the decision maker. Scripting puts the user, not the application, in the director's chair.
How to Get an Agent
Although traditional uses of scripting can help your application's run at the box office, your next blockbuster is likely to come from an emerging marketplace, such as mobile computing. One paradigm for mobile computing involves mobile agents. Mobile agents are programs that move about the network using available resources at various nodes. Users create the agents using software on laptop computers and on personal digital assistants. For example, a person at a basketball game might generate an agent that makes dinner reservations after the game. The software generates the agent based on the user's selections and sends the agent to the appropriate server. The agent itself would be a program written in a scripting language.
Mobile agents become especially interesting when they arrive at a server to do work. An agent must be able to use applications on the server. And, if your application is scriptable, an agent could use your application.
Casting Call: Why Object REXX?
The REXX language is enjoying a surge of popularity because it is powerful, flexible, easy to learn, and easy to use. The simplicity of the language encourages developers to write programs that would otherwise go unwritten. For OS/2 applications, REXX is the natural choice because it's in the base product.
REXX is also a great choice in network environments because it is implemented on many platforms and because the core language is portable. IBM has implementations of REXX available on OS/2, PC DOS, NetWare, AIX, OS/400, VM, MVS, CICS, and VSE. The new Object REXX is available on The Developer Connection for OS/2 CD-ROM. It is also being ported to other popular platforms. Moreover, Object REXX is the default Open Scripting Architecture (OSA) language for OS/2, which means that Object REXX can be used for OpenDoc scripting.
Act One: Wrapping Your Interfaces
There are varying degrees of scriptability. If your application is already written and includes a programming interface in the form of C language functions, you're in luck. You can add some scriptability to your application by making these same interfaces available as REXX functions.
To do this, you need to write a brief C-language wrapper for each of your interface functions. In its simplest form, the wrapper is a translation layer between REXX and your C-language interface. The wrapper accepts REXX string arguments, converts those arguments to data types appropriate for your C-language interface, calls the C-language interface, and returns the results as REXX strings.
Figure 1. Wrapping C-language functions
The REXX strings are passed to your C-language wrapper using a structure named RXSTRING. RXSTRING is defined in an IBM-supplied header file named REXXSAA.H. REXXSAA.H also contains the type definitions, function prototypes, and constants necessary for writing external functions. Your wrapper must have an #include directive for REXXSAA.H.
Your wrappers don't have to be limited to translation. You can expand their roles by using C-language functions included with REXX that access REXX variables, queues, and the REXX macrospace (for loading your functions into memory).
To make your wrappers available for use by any REXX procedure, package them as a dynamic link library (DLL). You'll also need to write a brief C-language program that registers the functions with REXX. For each of your wrapped functions, call the RexxRegisterFunctionDll function (supplied on The Developer Connection for OS/2 CD-ROM). Then make the program available for general use as an EXE file.
To use your DLL, REXX programmers would execute the registration program before using the wrapped functions, as shown in the following example:
/* REXX script to use Robobob functions */ robobob /* Invoke ROBOBOB EXE to register functions */ /* ROBOBOB calls RexxRegisterFunctionDll */ /* for each ROBOBOB function, such as */ /* ROBOWALK */ rc=roboWalk(10) /* Tell ROBOBOB to walk 10 paces */
Sample Code 1 Using external functions
Once your application registers a function using RexxRegisterFunctionDll, that function is available from all OS/2 sessions. You don't need to register the function again on subsequent invocations. Any REXX program can access a DLL external function after it is registered.
Making C-language interfaces available in a DLL is great if the application itself doesn't need to be running for the functions to work (that is, the functions are stand-alone functions similar to the REXX utility functions included with OS/2, such as SYSMKDIR).
But what if your application must be running? Many applications, such as editors and spreadsheets, fall into this category. In these cases, not only must you wrap and register the interfaces, you must be able to call the REXX interpreter as well. The REXX interpreter is a dynamic link library routine It is fully re-entrant and supports REXX procedures running on multiple threads in the same process. When your application calls REXX, REXX acts as a macro processor for your application.
When you intend to use REXX as a macro processor, package your external functions in the same module (EXE or DLL) as your application. By doing so, you prevent users from calling the functions without first starting the application. Use RexxRegisterFunctionExe to register the functions instead of RexxRegisterFunctionDll. Functions registered using RexxRegisterFunctionExe are available only to REXX procedures that are called from the registering application.
You'll also want to consider making application interfaces available through a subcommand handler instead of (or in addition to) external functions. Using a subcommand handler is expedient if your application already has a command language. When you provide a subcommand handler, users issue application commands directly from REXX procedures (just as they would issue OS/2 commands). The difference is that users would issue REXX ADDRESS instructions to direct the commands to an environment (your subcommand handler) that you register with REXX. Use RexxRegisterSubcomExe to register your subcommand handler.
REXX passes commands to your subcommand handler as REXX strings (RXSTRINGs) The subcommand handler uses existing application functions to process the commands, and returns results as REXX strings.
The following figure summarizes how REXX can function as a macro processor for your language:
Figure 2. REXX as a macro processor
Act Two: Doing Some Modeling
Object REXX provides several other alternatives for making your applications scriptable. One attractive alternative for existing applications is object modelling.
With object modelling, you analyse your application in terms of objects. Suppose your application is a server that uses TCP/IP sockets. One way to look at the communications is that each socket is an instance of a socket class. You could create a SOM class for sockets and SOM methods for the functions related to sockets, and then use those methods to interact with the socket objects.
One advantage is that SOM can keep state data for a particular instance of an object. With external functions, the function code typically wouldn't keep state data. The person writing the REXX procedure would have to maintain any state data across calls. Because the state data is maintained with the object itself, the complexity of scripting procedures is reduced.
Once the objects and methods are stored in SOM, they can be used from Object REXX. The beauty of this setup is that people who are scripting your application work with it in the same way that you do by sending messages to objects You don't have to provide a translation layer (wrapper). Moreover, the new Direct-to-SOM compilers greatly improve the usability of SOM. If your code is written in C++, you no longer need to build the classes separately with SOM's Interface Definition Language (IDL).
If you use object modelling and SOM to make your application scriptable, use only the SOM data types. When REXX interacts with SOM, it automatically performs data conversion between internal REXX data types and SOM data types. If you use some other data type, REXX may not be able to convert the data.
Act Three: Shedding Disguises
When designing a new application, you can use a technique known as factoring to make your application scriptable with Object REXX. In a completely factored application, all of the functions available from the user interface are also available from a script In effect, the user interface can be replaced by a script.
To factor an application, design it so that the objects and methods for the user interface are separate from the objects and methods that form the core of the application. The methods for the user interface should not, themselves, do any of the application's core functions. Instead, the interface methods should send messages to the core objects.
Assuming you use SOM for the core objects and methods, you can script the application by using Object REXX to send messages to the core objects. It doesn't matter that the message is sent from Object REXX instead of the user interface. In either case, the same method is run, yielding identical results.
Consider, for example, a Save selection on an editor pull-down menu. In a traditional application, the routine that gets control when the user selects Save would open the file, write it, and close the file. To make the Save function available to a script, additional work would be needed (as described in "Act One: Wrapping Your Interfaces").
In a factored application, the method that handles the Save event would not, itself, write the file Instead, it would send a message (perhaps SAVE) to an appropriate core object (perhaps an instance of a TEXTFILE class). Assuming SOM is used for the objects and methods, an Object REXX procedure could also send a SAVE message to an instance of the TEXTFILE class, as shown in the following figure:
Figure 3. Scripting a factored application
Movie sequels use familiar characters in new settings, solving new problems. Unfortunately, sequels are not always satisfying. But for applications, a sequel is precisely what you want; that is, you want your objects and methods being used in new settings and solving new problems.
When designing new applications, think in terms of discrete, reusable components. You can increase the value provided by your application by making these components available to your users for scripting. What objects would others find useful? Message repositories, user interface elements, clock objects - the list is endless.
Object REXX itself is a reusable component constructed of other reusable components. The various classes that Object REXX provides (ARRAY, STREAM, STRING, and so on) are reusable in any Object REXX script.
Your application can also play a leading role in reuse. All it takes is a bit of scripting with Object REXX.
Note: For details of the C language functions that interface with REXX, view the online documentation included on The Developer Connection for OS/2 CD-ROM. Object REXX is in the Development Tools category. View the Object REXX READ.ME file for information on getting started and for the latest technical updates.
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Reprinted from Volume 7 of The Developer Connection News