With V3R2 and V3R7, the AS/400 gained the ability to deliver graphical applications to anyone in the world through the Internet. This new HTML interface requires a lot less work than you might think.... That's right, much less work than you might think. The technique uses the same
RPG you're used to using, basically replacing DDS with HTML. I think you'll find HTML more intuitive than DDS. The result is that your applications gain both a graphical interface and exposure to the whole world (the Internet), and the programming effort is about the same as if you were programming for your local users. Sound too good to be true? Read on and believe.
The sample application I've written is relatively simple. To place an order for a widget, a customer enters information about himself. If any of the required fields, such as Name or City are left blank, the application returns error messages to the customer, informing him that he left a required field blank. If all required fields are completed, the application displays a "Thank You" message and writes the record to the ORDERS file.
Figure 1 illustrates what the data entry form might look like after a customer enters information. (The source code is shown in Figure 2.) After the appropriate information is entered, the user clicks the Submit button, which invokes the RPG CGI program on the AS/400. The CGI program performs six basic functions:
1. Reads the HTML form
2. Maps the HTML form input fields to the appropriate database fields
3. Edits the information
4. Builds a response form
5. Writes the response form to the Web browser
6. If the information is correct, writes the information to an AS/400 file
There is also a Clear button on the order form, which (you guessed it) clears the form of any information entered.
In order to process information from a Web browser, an HTTP server must be configured on your AS/400. In this case, I'm using IBM's HTTP Web server. To find out how to configure this server, see the OS/400 TCP/IP Configuration and Reference manual.
To read from and write to a Web browser, a simple input and output mechanism known in the DOS and UNIX world as standard input (stdin) and standard output (stdout) is used. Reading from standard input retrieves data from the Web browser; writing to standard output writes data to the Web browser. Since RPG doesn't natively support standard input and standard output, you must use two APIs supplied by IBM: Read from stdin (QTMHRDSTIN) and Write to stdout (QTMHWRSTOUT).
Before the RPG CGI program can read from the browser, it must, of course, be invoked. With host-based AS/400 data entry programs, you typically activate your program to display a data entry form. With a browser, the data entry form is displayed first, and then the data entry program is activated. The RPG program is actually started when the user clicks on the Submit button on the HTML form. The ACTION attribute of the FORM element specifies a URL to which the contents of the form are submitted. In this case, the URL specifies the location of the RPG CGI program IE003RG (see Figure 3), which receives the input.
The first thing the IE003RG does is perform a call bound (CALLB) procedure operation to the Read stdin API (QTMHRDSTIN) to retrieve the data that the user keyed. You can find this call in the ReadStdIn subroutine in Figure 3. Four parameters are used:
* RcvDta contains the data received.
* RcvDtaLen contains the length of the RcvDta variable.
* RcvValLen contains the length of the value returned.
* QUSEC contains error status information.
I included the QUSEC data structure from the QRPGLESRC file in library QSYSINC through a /COPY statement. You can use the QUSEC data structure for most of the APIs capable of returning error information. See the System API Reference manual for more information about the data structure and how to interpret the information it returns.
A CGI program receives the data from an HTML form as one long string of information, with embedded special characters. The information must be parsed before you can use it. Fortunately for us, IBM has provided an API to do all the dirty work. The only requirement is that the input field names in the HTML form that you want to move into your database match the DB2/400 database field names. You don't even have to do any MOVE operations.
The API is called Convert to DB (QTMHCVTDB). IE003RG calls the QTMHCVTDB API in the CvttoDB subroutine. Eight parameters are used:
* Qfile-qualified database file name
* RcvDta-input string
* RcvDtaLen-length of input string
* IESRDS-response variable
* FmtLen-length of record format
* RcvValLen-length of response variable
* CvtStat -response code
* QUSEC-contains error status information
I set up the Qfile parameter with a data structure. I define the RcvDta variable with a length of 1024 and then initialize the Rcv-DtaLen variable with a value of 1024. ORDERSDS is the data structure of the output record. As you can see in the program's D-specs, I've simply defined ORDERSDS as an external data structure that references the external file, ORDERS, through the EXTNAME keyword. I've also specified the external file format name (PRDORD) to be used. I initialize the RcdLen variable with a value of 393, because the length of the database file record is 393. CvtStat is an output parameter that returns a value to indicate the status of the conversion.
See the TCP/IP Configuration and Reference manual for more information regarding the response codes returned by the QTMHCVTDB API.
As mentioned earlier, QUSEC contains information about error conditions. See the System API Reference manual for more information on that subject.
Now that the information returned by the Web browser is parsed and mapped, the program can write the information to the database. However, to prevent bad data from entering the database, the program checks the information and lets the user know about errors through an HTML response form that is written to the browser.
The response form will actually reflect two conditions: (1) when one or more of the required fields is blank (see Figure 4, where all required fields are blank) and (2) when all required fields have been filled in (see Figure 5). Both conditions are determined at runtime, so the response document must be built dynamically.
Before writing an HTML document to the browser, IE003RG loads the WrtDta buffer with an HTTP header (HTTPHeader). As you can see, HTTPHeader contains "Content-type: text/html." This tells the browser that a text HTML document will follow. Also notice that the program appends two new-line characters to the HTTP header. This lets the browser know that this is the last header record (more than one can be sent).
To build a dynamic HTML document, IE003RG reads a source member containing the foundation for the HTML response document. (There are other ways I could have done this to avoid having to read from a source physical file-such as using a compile-time table-but this method affords more flexibility. For example, it allows you to easily modify the HTML document.) The HTML source member name is IE003HT, and on my system, it is stored in source file HTMLSRC in library WEBLIB.
Before the program opens the file and reads it, the program overrides the file HTMLSRC to the appropriate source file and library through the QCMDEXC API. (The OvrCmd variable is initialized to contain the Override Database File [OVRDBF] command.) Once the override is performed, the file is opened and the program enters a read loop.
As you examine the LoadHTML subroutine, you can see that the SRCDTA field of each source record read is loaded into the WrtDta variable, after which a new-line character is appended. This is an easy way to avoid running over the maximum number of 254 characters that you can send to standard output without a new-line character. At the point that record number eight has been read, the first part of the response form is built (the heading). Now, the program must determine if there are any errors and report them. This is done through the EditForm subroutine. If any of the required fields are blank, a message is loaded, concatenated to the WrtDta variable with the appropriate array (ERRMSGS) element, and the error variable is set to 1 (true). If no errors are found, a "Thank you..." message is loaded.
Reading from the browser occurs through standard input (stdin); writing to the browser occurs through standard output (stdout). Since RPG doesn't natively support standard output, the Write to Standard Output (QTMHWRSTOUT) API is used. IE003RG calls the API in the WrttoHTTP subroutine. Only three parameters are used with the QTMHWRSTOUT API.
* WrtDta contains the data to be written.
* WrtDtaLen contains the length of the data.
* QUSEC contains error status information.
Writing to the database is exactly the same as writing to any DB2/400 file; however, the IE003RG program writes a record only if there are no errors. As you can see, I use the WRITE operation to the IESUBREQ record format if error = 0. The program also loads the CREATEDTE field with the current time stamp value before writing the record.
There are numerous security issues that you should consider before installing and activating any Internet application on your AS/400. I urge you to learn all you can about AS/400 security and to take the recommended security precautions before installing this application. See the reference list at the end of this article for more information about Internet security and the AS/400. Once you've addressed security issues, follow these steps:
1. Create a Web library. Later, you will see that I store just one HTML document in this library. I call my Web library WEBLIB.
2. Create a CGI library to contain your CGI programs, such as the IE003RG program used here. The CGI library can also contain other objects used by Internet applications, such as files. The idea is to keep Internet objects used by CGI programs in one library, reducing the number of libraries accessed by Internet users. I call my CGI library CGILIB. Remember that the name you choose will affect your HTTP server configuration.
3. The easiest way to create this application is to download the source code from the Midrange Computing Web site. (Although you could key the code from the figures included in this article, you can probably make better use of your time.) Download the code by clicking the link on this page, and transfer the source members to your AS/400.
4. Transfer or create the source code member for the HTML data entry form IE002HT (see Figure 2) in an IFS file system. The HTML file will be stored as a stream file (STMF). I put mine in the root ("/") file system in a directory I call HTML. You could put the source member in a source physical file in a library in the library file system (QSYS.LIB), but that would make it more difficult to reference. I put all of my HTML documents in the IFS, except the ones that I might want to read from a program, such as the one mentioned in the next paragraph.
5. Transfer or create source code member IE003HT for the HTML response document (see Figure 6) in a source physical file in your Web library (I used a source file called HTMLSRC in a library named WEBLIB). Placing this response document shell in a source physical file makes it much easier to read from an RPG program.
6. Transfer or create the DDS for the ORDERS file (see Figure 7).
7. Transfer or create the source code for the RPG CGI program (see Figure 3).
8. Create a binding directory (I called mine CGIBNDDIR) with the Create Binding Directory (CRTBNDDIR) command in your CGI library.
CRTBNDDIR BNDDIR(CGILIB/CGIBNDDIR)
9. Copy the QTMHCGI service program from the QTCP library to your CGI library.
CRTDUPOBJ OBJ(QTMHCGI) +
FROMLIB(QTCP) +
OBJTYPE(*SRVPGM) +
TOLIB(CGILIB)
10. Place the QTMHCGI service program in the CGIBNDDIR binding directory.
ADDBNDDIRE BNDDIR(CGILIB/CGIBNDDIR) +
OBJ((CGILIB/QTMHCGI))
11. Be sure your Web library containing your HTMLSRC file and the library containing your ORDERS file are in your library list.
12. Create the RPG program IE003RG according to the instructions at the beginning of the source member.
13. For security reasons, be sure to exclude authority to *PUBLIC for your CGI library, the library containing the database file, the IE003RG program, and the ORDERS file. Grant authority to the QTMHHTP1 user profile to read and execute the RPG CGI program (IE003RG). Grant authority to the QTMHHTP1 user profile to read, execute, and write to file ORDERS.
14. Grant authority to the QTMHHTTP user profile to read and execute the subscription order form, IE002HT.
Now, all you have to do is point your browser to the URL that contains the subscription order form (e.g., http://myas400/html/ie002ht.htm), and you can run the application.
I think it's absolutely amazing (okay, maybe just great...remember, I've coded DDS for years) that you can serve your applications so easily to the Internet or an intranet. I mean, you can create a graphical interface that can be delivered to basically any desktop (e.g., Windows PCs,
Macintoshes, network computers, you name it); and you can do it with a pretty intuitive language-HTML. If network stations replace terminals, as I think they will, I believe there's a good chance that an HTML interface will become the interface of choice for many AS/400 programmers.
Richard Shaler is the editor of Midrange Computing magazine. You can reach him by email at shaler@midrangecomputing. com.
AS/400 System API Reference V3R6 (SC41-4801, CD-ROM QBKAMA00)
OS/400 TCP/IP Configuration and Reference V3 (SC41-3420, CD-ROM QBKANL03)
AS/400 Tips and Tools for Securing Your AS/400 (SC41-3300, CD-ROM QBKACF01)
Cool Title About the AS/400 and Internet (SG24-4815, CD-ROM EZ30AD01)
"How to Latch Down IBM's AS/400 HTTP Web Server," AS/400 Internet Expert, Feb/Mar 1997
"How to Reduce the Security Risk of the Internet," AS/400 Internet Expert, Feb/Mar 1997
OS/400 Security-Basic V3R7 (SC41-4301, CD-ROM QBJALB00)
OS/400 Security-Reference V3R7 (SC41-4302, CD-ROM QBJALC01)
Securing Your AS/400 from Harm on the Internet (SG24-4929, CD-ROM SG244929)
Figure 1: HTML form used for data entry
Widget Manufacturing, Inc.
Widget Order Form
Name:
Title:
Company Name:
Address:
Address:
City:
State:
Zip/Postal Code:
Country:
E-mail:
Phone:
Fax:
P.O.#:
ÿ �����
*===============================================================
* To compile:
*
* 1. CRTBNDDIR BNDDIR(CGI/CGIBNDDIR)
*
* 2. CRTDUPOBJ OBJ(QTMHCGI)
* FROMLIB(QTCP)
* OBJTYPE(*SRVPGM)
* TOLIB(CGI)
* 3. ADDBNDDIRE BNDDIR(CGI/CGIBNDDIR) OBJ((CGI/QTMHCGI))
*
* 4. CRTBNDRPG PGM(CGILIB/IE003RG)
* SRCFILE(*LIBL/QRPGLESRC)
* DFTACTGRP(*NO)
* BNDDIR(CGI/CGIBNDDIR)
*
*===============================================================
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
FHTMLSRC IF E DISK RENAME(HTMLSRC:SRCREC) USROPN
FORDERS O A E DISK
* Override command to get the correct HTML member
D OvrCmd s 60 INZ('OVRDBF FILE(HTMLSRC) +
D TOFILE(WEBLIB/HTMLSRC) +
Figure 3: RPG IV CGI Program IE000RG
D MBR(IE003HT)')
D OvrCmdLen s 15 5 INZ(60)
D ErrMsgs S 80 DIM(8) PERRCD(1)
D CTDATA
D WrtDta S 1024
D WrtDtaLen S 9B 0
D RcvDta S 1024
D RcvDtaLen S 9B 0 INZ(1024)
D RcvValLen S 9B 0
D CvtStat S 9B 0
D TimeStamp S Z
DCtr S 3P0
D Error S 1S 0
* HTML code contants
DHTTPHeader C Const('Content-type: text/html')
DNewLine C Const(X'15')
D/COPY QSYSINC/QRPGLESRC,QUSEC
D ORDERSDS E DS EXTNAME(ORDERS:PRDORD)
D QFile DS
D File 1 10 INZ('ORDERS ')
D Lib 11 20 INZ('CGI ')
D FmtLen S 9B 0 INZ(393)
* Read standard input
C exsr ReadStdIn
* Convert HTML input to DB2/400
C exsr CvttoDB
* Write the HTTP header, to let the browser know a document is coming
C movel(P) HTTPHeader WrtDta
C cat NewLine:0 WrtDta
C cat Newline:0 WrtDta
* Build HTML document
C exsr LoadHTML
* Write HTML document
C exsr WrttoHTTP
* If there were no errors found, write to DB2
C if error = 0
C time TimeStamp
C eval CREATEDTE=TimeStamp
C write PRDORD
C endif
C eval *INLR = *On
*===============================================================
C ReadStdIn begsr
C callb 'QtmhRdStin'
C parm RcvDta
C parm RcvDtaLen
C parm RcvValLen
C parm QUSEC
C endsr
*===============================================================
C CvttoDB begsr
C callb 'QtmhCvtDb'
C parm QFile
C parm RcvDta
C parm RcvDtaLen
C parm ORDERSDS
C parm FmtLen
C parm RcvValLen
C parm CvtStat
C parm QUSEC
C endsr
*===============================================================
C WrttoHTTP begsr
C ' ' checkr WrtDta:1024 WrtDtaLen
C callb 'QtmhWrStout'
C parm WrtDta
C parm WrtDtaLen
C parm QUSEC
C eval WrtDta = *blanks
C endsr
*===============================================================
C LoadHTML begsr
C eval Ctr = 0
* Override to the correct source member
C call 'QCMDEXC'
C parm OvrCmd
C parm OvrCmdLen
* Read source member and build HTML document
C open htmlsrc
C read htmlsrc 50
C dow *in50 = *off
C eval Ctr=Ctr+1
C if SRCDTA *BLANKS
C cat SRCDTA:0 WrtDta
C cat NewLine:0 WrtDta
C if ctr=8
C exsr EditForm
C endif
C endif
C read htmlsrc 50
C enddo
C close htmlsrc
C endsr
*===============================================================
C EditForm begsr
C eval error = 0
C if NAME = *BLANKS
C cat ERRMSGS(1):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if CONAME = *BLANKS
C cat ERRMSGS(2):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if ADDRESS1 = *BLANKS
C cat ERRMSGS(3):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if CITY = *BLANKS
C cat ERRMSGS(4):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if ZIPPOSTCDE = *BLANKS
C cat ERRMSGS(5):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if COUNTRY = *BLANKS
C cat ERRMSGS(6):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if EMAIL = *BLANKS
C cat ERRMSGS(7):0 WrtDta
C cat NewLine:0 WrtDta
C eval error = 1
C endif
C if error = 0
C cat ERRMSGS(8):0 WrtDta
C cat NewLine:0 WrtDta
C endif
C endsr
*===============================================================
*. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8
**CTDATA ERRMSGS
You must enter your
Name.
You must enter your
Company Name.
You must enter at least one line of your
Address
You must enter your
City.
You must enter your
Zip or Postal Code.
You must enter your
Country.
You must enter your
Email Address.
Thank you for your subscription order.
Figure 4: Subscription order response form, with errors
Figure 5: Order response form, no errors
Widget Order Response
Use your browser's
Back
tool to return to the order form.
Return to Midrange Computing homepage.
Figure 7: DDS for file ORDERS
A R PRDORD
A NAME 40 TEXT('Name')
A TITLE 40 TEXT('Title')
A CONAME 40 TEXT('Company name')
A ADDRESS1 40 TEXT('Address line 1')
A ADDRESS2 40 TEXT('Address line 2')
A CITY 30 TEXT('City')
A STATE 2 TEXT('State')
A ZIPPOSTCDE 10 TEXT('Zip or Postal Code')
A COUNTRY 20 TEXT('Country')
A EMAIL 40 TEXT('Email Address')
A PHONE 20 TEXT('Telephone number')
A FAX 20 TEXT('Fax Number')
A PONUMB 25 TEXT('Purchase order num')
A CREATEDTE Z TEXT('Created Date')
LATEST COMMENTS
MC Press Online