In my previous article ("How Does RPG Talk to a Browser"), I discussed how to configure an HTTP server and how to create a simple RPG program to write a page to a browser. I also mentioned that you needed to have masochistic tendencies if you wanted to learn the intricacies of learning the CGI APIs, especially when there is a free alternative from IBM. Yes, the words "free" and "IBM" were together in the previous sentence!
Back in 1996 Mel Rothman, then working with IBM's Partners in Development (PID) group, developed the original CGIDEV, also known as Easy400. Since then, CGIDEV has gone through multiple enhancements and developments (now CGIDEV2) from Mel and Giovanni Perotti of IBM Italy. Although Mel has since left IBM, you will still find him (along with Giovanni) answering questions and offering advice on the Easy400 group at http://groups.yahoo.com/group/Easy400Group/.
So what is CGIDEV2? The simplest description is that it is a set of subprocedures that make the CGI APIs easy to use and allow you to have HTML externally described for an RPG program. On top of the simple description you can add a host of other tools (for e-mail and security), a few sample applications and a handful of tutorials to make your integration of RPG and the Web an easy one. If you want to get a feel for what CGIDEV2 has to offer, go to http://www-922.ibm.com, follow the Deliverables link (on the left) and click on the RPG CGI program development toolset link. Have a look at any of the offerings on the resulting page.
The first thing to do is get your hands on CGIDEV2. Follow the Downloads link and click on the ILE-RPG CGI Development Kit (CGIDEV2) link. Unzip the downloaded file and follow the instructions in the Readme document. Basically, you will FTP a save file to your iSeries, restore a library and run a couple of setup programs that will re-create the CGIDEV2 programs, create required directories and create an Apache server (or traditional server if you are still on V5R1). Make sure you follow the instructions at the top of the configuration file displayed during the install process.
You may want to download and install some of the other offerings: I recommend a minimum of the E-Commerce CGI Centaur Demo (an application along the lines of Amazon, complete with source code) and the HTML and CGI Self-Study Class.
Take a couple of hours to look at what you have installed. Have a look at the Yacht World demo that is installed as part of CGIDEV2. Then have a go at creating your own CGIDEV2 program. You can use some of the templates provided or you may want to try the following which is a simple "print" style program that produces a Web page like the one shown in Figure 1. This program simply lists the contents of a database to the Web page, but since we are using HTML, it seemed like a good idea to include a picture of the items being listed. Why not change the code to use one of your databases?
Figure 1: Output from a simple "print" style CGI program
What do you need?
You will need a library to contain your CGI programs: I am using a library called CGISEMINAR. Copy the service program CGISRVPGM2 from the CGIDEV2 library and copy the source member PROTOTYPEB from QRPGLESRC. To make life easier, create a binding directory and add an entry for the service program. Make sure you include the library name with the service program because CGI programs cannot depend on library lists at run time. Rather than copying objects and sources from CGIDEV2 you could, of course, simply reference them directly, but that could lead to complications further down the road if you install a later release of CGIDEV2.
You will need a directory in the root file system to store HTML documents, style sheets, images and anything else you can think of: I am using a directory called cgiseminar. The images of the items are in a subdirectory called images: each image is a JPG and the name is a 'P' followed by the product code, e.g. the image for product 0000001 is P0000001.JPG. It is possible to store HTML documents as source members in a source physical file, but I have always found it easier to develop them on a PC and simply copy them to a directory on the IFS.
Finally, you need to configure an HTTP server to use. The server should send all CGI requests to the library mentioned above. (Please refer to "How Does RPG Talk to a Browser" for detail on configuring an HTTP server.) In my example I am mapping the default CGI director of cgi-bin to the library QSYS.LIB/CGISEMINAR.LIB.
Start by designing your Web page using your favourite HTML tool: Websphere Studio, Dreamweaver, Frontpage, Notepad or whatever takes your fancy. This HTML document is named CVALLREP1.HTML, and it is kept in the cgiseminar directory.
The important thing to remember when designing a Web page that will be written to from a program is to only define a repeating line once. Think of the way you define a print file; you only define one record for printing and write it multiple times. In the example in Figure 2 there is the definition of one product line.
When you have the Web page looking the way you want, it is time to add the CGIDEV2 bits. That means adding the equivalent of format names and field names.
In Figure 2 note the lines containing /$top, /$tableline and /$end. These are the three formats that will be written from the program. '/$' is used to indicate a format name, although you do have the option of changing this and using other characters. Likewise, fields are identified by enclosing the name between a '/%' and a '%/', as with /%today%/ and /%prodcd%/.
The other important point is the first line of HTML. This must be 'Content-type: text/html' followed by two carriage return/linefeed for HTML that will be written from a CGI program.
/$top **** START HTML Content-type: text/html <html> <!-- A simple paging report --> <head> <title>List Products by Category</title> <link rel="stylesheet" type = "text/css" href="/cgiseminar/StyleSheet.css"> </head> <body> <center> <h1>RPG Meets the Web!</h1> <b> Product list as at /%today%/ - Days Since Last Order</b><br><br> <table border=1 CellSpacing=2 CellPadding=2 Width="80%"> <b><th>Product<br>Code</th> <th>Description</th> <th></th> <th>Landed<br>Cost</th> <th>Selling<br>Price</th> <th>Date Last<br>Ordered</th> <th>Days Since<br>Last Ord</th></b> /$tableline **** Insert a Row <tr align=right> <td align=center>/%prodcd%/</td> <td align=left>/%prodds%/</td> <td><img border=0 src="/cgiseminar/Images/P/%prodcd%/.JPG"></td> <td>/%LndCst%/</td> <td>/%SellPr%/</td> <td align=center>/%DtLOrd%/</td> <td>/%dayssince%/</td> </tr> /$end **** END HTML </table></center> </body> </html>
Figure 2: HTML for a CGIDEV2 program
Figure 3 shows the source of the CGIDEV2 program CVALLREP1. The program makes use of three of the CGIDEV2 subprocedures: gethtmlIFS, wrtsection and updHTMLvar.
H Option(*SrcStmt: *NoDebugIO) DftActGrp(*No) BndDir('RPGBROWSE') FProduct1 IF E K Disk ExtFile('CGISEMINAR/PRODUCT1') /copy prototypeb D Today S D Inz(*Sys) D LastSold S D DatFmt(*MDY) D DaysSince S 5I 0 //============================================================= /Free gethtmlIFS('/cgiseminar/cvallrep1.html':'/$'); updHTMLvar('today':%char(today)); wrtsection('top'); Read Product1; DOW Not %EOF(Product1); updHTMLvar('prodcd':prodcd); updHTMLvar('prodds':prodds); updHTMLvar('lndcst':%Char(LndCst)); updHTMLvar('sellpr':%Char(SellPr)); If DTLORD <> 0; LastSold = %Date(DtlOrd:*YMD); DaysSince = %Diff(Today:LastSold:*Days); updHTMLvar('dtlord':%Char(lastsold)); updHTMLvar('dayssince':%Char(dayssince)); Else; updHTMLvar('dtlord':'No sales to date'); updHTMLvar('dayssince':'No sales to date'); EndIf; wrtsection('tableline'); Read Product1; EndDo; wrtsection('end'); wrtsection('*fini'); *InLR = *On; /End-Free
Figure 3: A simple CGIDEV2 program
The important items to note are as follows:
- The binding directory is specified on the H spec.
- The EXTFILE keyword is used to qualify the file name that will be used at run time. Remember, this program will run in a server job in the QHTTPSVR subsystem, and you should not rely on a library list.
- A copy directive is used to include the PROTOTYPEB member containing the CGIDEV2 prototypes.
- The program starts by calling the gethtmlIFS subprocedure to load the CVALLREP1.HTML document. Think of this as the equivalent of an OPEN operation in RPG. The second parameter allows you to specify the characters you are using to identify a section (format); in this case, the default of '/$'.
- The updHTMLvar subprocedure is used to copy the contents of a field to the HTML document. The first parameter is the name of the field in the html document (i.e. the name between a '/%' and a '%/') and the second parameter is the name of the field in the RPG program. The second parameter must always be passed as a character value, hence the use of the %CHAR BIF when copying the value of numeric or date fields. Also note how /%prodcd%/ is defined twice in the HTML (once for the product code and once for the image), but only one call to updHTMLvar is required to put a value in it.
- The wrtsection subprocedure is used to write a section of the HTML document. The logic of the program starts by writing the top section, writing the tableline section for each product record and finally the end section.
- At the very end there is a write of the special section *fini. This is the instruction to actually write the Web page and results in the complete document being sent to the requesting browser.
Running the program
Nothing could be simpler. Ensure that the server is running:
STRTCPSVR SERVER(*HTTP) HTTPSVR(RPGBROWSE)
Once the server is running, you open your browser and enter the URL of:
where iseriesservername is the name of your iSeries. All being well, the results of your efforts will be displayed in the browser.
By having the URL above as a link on a Web page you could have the information available to the user in the click of a mouse.
Up and running
Now you know how easy it is to have an RPG program use external HTML to write data to a browser. In the next article you will see how easy it is to get information from a browser to an RPG program. It may be time to start looking at ways to replace those maintenance programs!
About the author: Paul Tuohy is CEO of ComCon, an iSeries consulting company. He is the author of Re-Engineering RPG Legacy Applications and is one of the quoted industry experts in the IBM Redbook "Who Knew You Could Do That With RPG IV?"