Cal is founder of Main Event Software, publisher of the Scripter development tool. He can be reached at [email protected].
One of the best-kept secrets about the World Wide Web is the extent to which the Macintosh is used as a development platform. A survey of 13,000 Web users conducted earlier this year by the Graphics, Visualization, and Usability (GVU) Center at Georgia Tech University found that the MacHTTP server software is the second-most popular server package. MacHTTP has 20.8 percent of installations, trailing NCSA (38.6 percent), but ahead of CERN (18.5 percent), and significantly ahead of most other servers. (The study was conducted in April and May of this year, and focused on a number of topics, not just servers.)
In this article, I begin by discussing the principal aspects of the Macintosh as an Internet platform, and then describe how you can use the AppleScript language for writing CGI applications that run on Macintosh servers, and end with a quick look at alternatives to AppleScript.
Macintosh Servers
The current situation is highly subject to change, of course; competition among desktop server packages has escalated several notches recently, with the release of a slew of Windows-based server products over the summer. Nevertheless, it is worth reminding those who discount the Mac as an Internet platform that MacHTTP was the third Web server ever written, after NCSA and CERN (both of which run on UNIX only).
MacHTTP is shareware and available at a number of ftp repositories on the net. Recently, Chuck Shotton, the author of MacHTTP, revamped the program and turned it into a commercial product called "WebStar,'' marketed by StarNine Technologies (Berkeley, CA). The author claims that WebStar is about four times faster than MacHTTP, and can handle 500,000 hits per day on a PowerMac 7100. Two sites at Apple currently running WebStar are www.apple.com and quicktime.apple.com. According to Shotton, MacHTTP and WebStar together comprise 66 percent of the "commercial Web-server market."
Whether you use MacHTTP or Webstar, you can create CGI-style applications that don't rely on the cumbersome UNIX-style CGI interface, as defined by the NCSA and CERN servers. The advantage of traditional CGI is that it is supported in many servers on many platforms, not just NCSA and CERN. One disadvantage, at least on the Mac platform, is that it is not as effective a mechanism for interapplication communication (IAC) as using native facilities--namely, Apple Events.
Apple incorporated Apple Events into System 7 as an efficient and flexible means for applications to communicate with each other. MacHTTP and WebStar use Apple Events for a CGI-style interface between server and back-end processing. WebStar also uses Apple Events to implement remote-administration facilities, which allow the site administrator to monitor multiple server machines simultaneously from a single workstation: examining outputs, memory usage, connection status, and so on. The Apple Event-based CGI facility lets you write CGI applications using any scripting language that is compliant with Apple's Open Scripting Architecture (OSA). OSA defines a standard on the Macintosh that lets different languages access the same system-level facilities. This includes Apple's own AppleScript language, as well as languages from third parties such as UserTalk, or simple macro packages such as QuicKeys.
Of course, you can still write CGI applications using the traditional CGI facility. With MacPerl, the Macintosh implementation of the Perl scripting language, it is possible to port scripts originally written for UNIX servers, as long as they do not rely on UNIX-specific operating system calls or call UNIX-specific utilities. But in many cases, you are better off rewriting the program using an OSA-compliant language. The increased flexibility and performance make it worth your while.
About AppleScript
The AppleScript language in many ways resembles HyperTalk, the language used in Hypercard, except that it is not designed just for user-interface-intensive single applications. Instead, it is an object-oriented language that integrates multiple applications and interacts with system-level facilities in the Macintosh operating system. The AppleScript package from Apple consists of a language, a system-software extension, a simple scripting editor, and language additions. AppleScript is now a standard component of System 7.5, and therefore available to all users.
Using AppleScript, you can design work-flow applications that govern data flow from one program to another. If a program has been designed to be scriptable, AppleScript (and other OSA languages) has access, at a fine-grain level, to a range of object types within the application. For example, in the QuarkXPress page-layout program your scripts have access to specific paragraphs or graphics; in the FileMaker Pro database program, you can manipulate individual database records and fields. There are over a hundred more scriptable applications, including WebStar, Eudora, Netscape Navigator, and the MacOS Finder itself. As a result, power users and programmers can quickly put together end-user scenarios, be they simple or complex.
An Apple Event is a message (corresponding to an action) sent between two applications or between a scripting system and an application. The code in the target application is known as the "event handler." In a CGI communication between server and back-end application, the CGI arguments are represented by parameters to the Apple Event, and are identified by 4-byte IDs (see Table 1). The CGI application returns data by providing a "reply" to the Apple Event.
Within an AppleScript CGI script, you can process data or instructions entered into a form. You can initiate a database search, assemble text, and produce charts or graphics--all driven from user choices. In addition, you can send e-mail, assemble HTML pages on the fly, and deal with run-time errors.
Integrating multiple applications is accomplished through application-specific vocabularies housed within scriptable applications. A vocabulary extends AppleScript to include new terms representing actions and objects specific to the particular application. Together with AppleScript's built-in terms, you write scripts by putting together sentences that often resemble grammatically correct, English-language sentences rather than traditional C code.
A script consists of properties (the data) and handlers (the methods). AppleScript variables and properties are dynamically typed --their types are not declared and can change from statement to statement. Properties are initialized when the script is first run, and are updated each time a script completes. Example 1(a) shows a script that increments its counter every time it is run. Handlers (which either respond to an Apple-Event message or are analogous to subroutines in other languages) use one of two methods of specifying parameters: positional and keyword. For CGI use, the keyword form is employed.
An AppleScript CGI
In CGI scripts, the message sent by the Web server is handled by a "raw event handler," for which there are no terminology equivalents for the verb and parameter keywords. AppleScript provides a mechanism for specifying these terms using their 4-byte code values. In a declaration for a keyword handler, raw event and parameter codes are enclosed in "chevron" or "French quote" << >> characters. You don't need to specify all the CGI parameters in your handler declaration, only the ones you need. Example 1(b) shows the counter-incrementing script as a CGI program.
Moving to a more interesting example, suppose you maintain a regularly updated database of information that includes a table of numeric values, and you want to provide, on demand to your Web users, the table in the form of a chart. For this example, I'll use three familiar applications, FileMaker Pro (to hold the data), DeltaGraph Pro (to make a chart of the data), and Clip2Gif (to store the chart in a GIF file). You can use redirection ("Location" in the reply header) to point the Web server to the GIF file. The resulting CGI program is shown in Example 2.
AppleScript provides an interesting mechanism for handling errors known as a "try block," which resembles the TRY...CATCH construct in C and some other languages. Your regular application code goes in the first part of the try block; if an error occurs, the error-handling code in the second part of the try block is invoked. Example 3 shows a simple error handler that generates an HTML page by concatenating a bunch of strings.
Other Tools and Alternative Languages
There are a variety of small tools to simplify processing the data passed to an AppleScript CGI program by MacHTTP. These small tools are AppleScript scripting additions, colloquially referred to as "osax" in the singular, and "osaxen" in the plural. An osax extends the AppleScript command set by providing additional verb and parameter keywords to the vocabulary. Scripting additions work not just with AppleScript but with any OSA-compliant language.
Most CGI programs use HTML forms to pass in fields of data using particular formats. Various osaxen are used to process this data. For example, there is an osax for decoding URLs, and one that splits up the arguments into individual chunks (the Tokenize osax). There is also the "parse CGI" osax that combines many of the commonly used tasks in implementing CGI programs. The parse CGI osax can be used to decode, parse, and access the HTML form information that is passed in to an AppleScript CGI. It combines the functionality of the "DePlus," "Decode URL," and "Tokenize" osaxen to handle incoming HTML forms and field data.
How do you create, edit, and debug AppleScript code? As part of System 7.5, Apple provides a very simple Script Editor, offering basic editing functions. This editor allows you to write and edit text, and turn the text into scripts. There are also third-party tools, such as Scripter and FaceSpan.
Scripter, from my company, Main Event Software (Washington, DC), is an authoring and development environment that includes point-and-click access to the vocabularies in dictionaries of scriptable applications, an enhanced scripting editor, and integrated debugger of considerable depth, specifically designed for AppleScript. ScriptBase, also from Main Event, provides an object database for system-wide storage of values and objects that may need to be accessed from scripts.
FaceSpan, from Software Designs Unlimited of (Chapel Hill, NC), is a design tool for visual-interface-intensive applications, containing UI elements such as buttons, text boxes, lists, popups, menus, and gauges. FaceSpan applications can be built using AppleScript or another OSA-compliant language, such as Usertalk or QuicKeys.
Usertalk is the language used in the Aretha scripting environment from Userland Software. Aretha (Palo Alto, CA), formerly called "Frontier," actually predates AppleScript and was designed with similar goals: to provide a system-level facility for integrating applications. Usertalk is now OSA-compliant, so AppleScript and Usertalk code can be used interchangeably in the same script. Usertalk is considered by some to be more difficult to learn. It offers a multithreaded environment with an object database that can store both application data and scripts. The Aretha package used to be a commercial application but its author, Dave Winer, has recently made it free. The support is now handled by volunteers.
Conclusion
This whirlwind tour of scripting on the Macintosh platform gives you some idea of the facilities available for developing internetworked applications. As you explore further, you'll find that the tools have a flexibility and power that cannot be emulated on other platforms.
References
Apple Computer. Inside Macintosh: Interapplication Communication. Reading, MA: Addison-Wesley, 1994.
--------. AppleScript Language Reference Guide. Reading, MA: Addison-Wesley, 1994.
Goodman, Danny. Danny Goodman's Complete AppleScript Handbook. New York, NY: Random House, 1994.
Two internet mailing lists, available via [email protected], are applescript-users (for writers of scripts), and applescript-implementors (for developers of scriptable apps).
Table 1: The parameters for the Apple Event WWWdoc, a custom event sent by the Web server.
Example 1: (a) A simple script that increments a counter; (b) the equivalent script as a CGI program.
Example 2: A CGI program that generates a chart on the fly from a database.
Example 3: A simple error handler.
Copyright © 1995, Dr. Dobb's Journal
<b>
Code Suggested name Description </b>
---- path_args Data in URL following "$"
kfor http_search_args Data in URL passed using GET method, or
following "?"
post post_args Data in URL passed using POST method
meth method Which argument to use: GET (search args)
or POST (post args)
addr client_address The client's IP address (or DNS)
user username The client's user name (if using security)
pass password The client's password (if using security)
frmu from_user Additional user information (often an
e-mail address)
svnm server_name The server's name (MacHTTP or WebSTAR)
svpt server_port The server's port
scnm script_name The URL sent to the server
refr referer The URL the client was viewing before
the current one
Agnt user_agent The client software's name
ctyp content_type MIME content type of post args
Kact action Method of calling CGI: PREPROCESSOR,
POSTPROCESSOR, CGI, or ACGI
Kapt action_path If present, path to file from disk root
(used for ACTIONS), defaults to
script_name
Kcip client_ip The client's IP address (present even if
NO_DNS is false)
Kfrq full_request Full text of client's request
(a)
property counter : 0
on run
-- The run handler is executed each time
-- a script is run or launched.
set counter to counter + 1
end run
(b)
property counter : 0
-- The run handler is executed when the CGI is
-- launched. But if the CGI is already running when
-- the special Apple event fires, the run handler isn't run.
on run
-- This handler is optional in a CGI
-- If you have any initialization code, it goes here
end run
-- This is the CGI Handler receiving the arguments from the Web server.
-- This handler has the same form as any other handler.
-- In this example we only handle five of the 18 CGI parameters,
-- the direct parameter plus four others.
on <<event WWWdoc>> path_args ¬
given <<class post>>:post_args, <<class meth>>:method, <<class addr>>:client_address
-- CGI body goes here
set counter to counter + 1
end <<event WWWdoc>>
property crlf : (ASCII character 13) & (ASCII character 10)
property reply_header : "HTTP/1.0 302 FOUND" & crlf & ¬
"Server: WebSTAR/1.0 ID/ACGI" & crlf & ¬
"Location: http://www.your.site/home.html" & crlf & ¬
"URI: http://www.your.site/home.html" & crlf & ¬
crlf
-- This is the CGI Handler
on <<event WWWdoc>> path_args ¬
given <<class post>>:post_args, ¬
<<class meth>>:method, ¬
<<class addr>>:client_address
-- Interpret CGI arguments. Here you would obtain the
-- user's choices from the arguments.
-- After this, the next step is to retrieve data from database
tell application "FileMaker Pro"
Open alias "Macintosh HD:Databases folder:Web DataBase"
set numRecs to Count of Record in Document 1
-- Make tab-delimited data for Deltagraph
set dataString to "Month" & tab & "Amount" & return
repeat with i from 1 to numRecs
copy dataString & Cell "month" of Record i ¬
& tab & Cell "amount" of Record i ¬
& return to dataString
end repeat
end tell
-- Create the desired chart
tell application "Deltagraph Pro"
Data dataString
Plot Options Text Font "Palatino" Text Size 12 ¬
Colorstyle "blue"
Set Axis Lengths for X 100 for Y 100
Output PICT
set dataChart to Plot chart chartType
end tell
-- Make the GIF file for the redirect
tell application "clip2gif"
save dataChart as GIF in file "Macintosh HD:home.html"
end tell
-- Return the reply data to the server and exit the CGI handler
return reply_header -- reply and exit
end <<event WWWdoc>>
property crlf : (ASCII character 13) & (ASCII character 10)
property http_header : "HTTP/1.0 200 OK" & crlf ¬
& "Server: WebSTAR/1.0 ID/ACGI" & crlf ¬
& "MIME-Version: 1.0" & crlf & "Content-type: text/html" ¬
& crlf & crlf
-- The CGI Handler
on <<event WWWdoc>> path_args ¬
given <<class post>>:post_args, ¬
<<class meth>>:method, ¬
<<class addr>>:client_address
-- Enclose your CGI code in a "try/on error/end try" construct
try
-- Put the body of your CGI here.
on error errNum number errMsg
-- If there's an error, the error-handling
-- mechanism will drop you in here:
-- Create a page of HTML text to return.
set return_page to http_header ¬
& "<html><head><title>Error Page</title></head>" ¬
& "<body><h1>Error Encountered!</h1>" & return ¬
& "An error was encountered while trying " ¬
& "to run this script." ¬
& return
set return_page to return_page ¬
& "<H3>Error Message</H3>" & return ¬
& errMsg & return ¬
& "<H3>Error Number</H3>" & return ¬
& errNum & return ¬
& "<H3>Date</H3>" & return ¬
& (current date) ¬
& return
set return_page to return_page ¬
& "<hr>Please notify the webmaster at " ¬
& "<a href=\"mailto:[email protected]\">" ¬
& "mailto:[email protected]</a> " ¬
& "of this error." ¬
& "</body></html>" ¬
& return
-- Return the error page created and exit the handler.
return return_page
end try
end <<event WWWdoc>>