PreviousReusing Legacy Code CGI, ISAPI and NSAPI ProgramsNext

Chapter 7: Server-side Programming

This chapter describes how you write server-side programs for Internet applications. These apply equally to ISAPI, NSAPI and CGI programming.

7.1 Overview

Net Express provides extensions to COBOL which make it much easier to write Internet server-side programs than with other languages. You can receive data from a form using the ACCEPT verb, and send a result back to a Web browser using either the DISPLAY verb or Embedded HTML (EHTML). EHTML enables you to construct HTML pages on the fly from within a COBOL program. This chapter covers four main areas:

When you use Form Designer to paint your HTML forms, the Internet Application Wizard can generate the skeleton of a server-side program to read in the data, and return a result. You can then fill in the additional code to process the data. This means that you can start creating applications without needing to know the detailed syntax for receiving input and returning output, although this information is useful when you start creating more sophisticated applications.

The server-side programs generated by the Internet Application Wizard use ACCEPT to receive data from a form, and EHTML to display a form.

7.2 Resource Contentions

A server-side program can be executing simultaneously several times for different users. If it is a CGI program, each time the program is executed it runs as a separate process; if it is an ISAPI or NSAPI program, each time it is executed it runs in a separate thread. If your server-side program needs to access shared resources (for example files and databases), you must include logic to handle resource contentions.

COBOL includes a rich set of functions for sharing files. For more information, see the chapter Sharing Files in File Handling.

7.3 Input to a Server-Side Program

Each control on a form has a name and a value. As explained in the chapter Forms and HTML, when the end-user submits the form, the information on the form is sent to the server-side program as a set of name/value pairs. Extensions to COBOL syntax enable you to associate the names of the controls on the form directly with COBOL data items in your server-side program. When the data in the form is posted to the server-side program, the data items are set to the values of the controls on the form.

The form below has a field that has been named "name". The end-user types in the value "Bob".

field with form named 'name'

Figure 7-1 Example form showing field names

The server-side program ties into each of the named controls by having a declaration like this in Working-Storage:

01 inputdata is external-form.
   03 name-field      pic x(30) identified by "name".
   03 email           pic x(15) identified by "emailid".
   03 phone-no        pic x(30) identified by "phone".
 

When the server-side program is run by the end-user clicking the Send Form button (which is the Submit control in this example), the value Bob is transferred into data item NAME-FIELD when the following statement is executed:

accept input-form

When you create a form with Form Designer, it can generate a skeleton server-side application for you, with a copyfile which declares the data items you need to match up to each of the controls on the form.

7.3.1 Syntax

Use the following syntax to map a COBOL data item to CGI input:

level-number data-name-1 IS EXTERNAL-FORM.

This declaration says that group item data-name-1 and its subordinate fields can have their values set by input from an HTML form. To map elementary data items to NAME attributes.

sub-level-number data-name-2 picture-string IDENTIFIED BY name.

where the parameters are:

sub-level-number A COBOL data item level number.
data-name-2 A COBOL data name.
picture-string A COBOL picture string. PIC X(n), PIC 9(n), and numeric edited fields are allowed. Strings longer than n characters are truncated, strings less than n characters are padded from the left with spaces.
name The value of a Name or Groupname property on the corresponding control on the Form.

7.3.2 Example

This example shows a set of data items mapped to the fields on a form.

01 input-form is external-form.
    03  name-field pic x(30) identified by "Name".
    03  phone-no   pic x(30) identified by "Phone".
    03  email      pic x(15) identified by "EmailID".

7.4 Output from a Server-side Program

Net Express provides two alternative methods for outputting HTML from a COBOL program to a Web browser. Both methods enable you to substitute the values of COBOL variables into the HTML output:

7.4.1 Using EHTML

Embedded HTML (EHTML) enables you to output HTML directly from a COBOL program. The server-side programs generated by the Internet Application Wizard both use EHTML to return results to the end-user.

EHTML enables you to include complete HTML pages as copyfiles inside your program but with the advantage that you don't need any special data declarations. You can also use partial HTML pages as copyfiles, or output individual HTML statements, and build up a complete page under complete program control. This gives you tremendous flexibility.

You embed HTML into a COBOL program by using the EXEC HTML statement. This is translated by the EHTML preprocessor, htmlpp.

The EXEC HTML and END-EXEC keywords enable you to embed HTML directly into your COBOL source code. You must put keywords EXEC and HTML on the same line; otherwise there are no formatting restrictions.

This is the general format:

EXEC HTML
  [htmloutput] 
  [copy "file.htm".]
END-EXEC

where the parameters are:

htmloutput HTML markup for output to a Web browser.
file.htm A file containing HTML markup

The EHTML preprocessor does not validate or parse your HTML markup - it just outputs it directly to the Web server which started the CGI program.

With fixed format COBOL source code, the EHTML preprocessor treats column 8 as a virtual column 1 when outputting embedded HTML. This simplifies use of the HTML <PRE> tag. However, if you include a copyfile with an extension of .htm, the preprocessor treats the copyfile as free format source. You can override this behavior with the preprocessor directive, NOAUTOFORMAT.

7.4.1.1 Substitution Markers

You can substitute variable data from your COBOL program directly into the HTML output by using substitution markers. Substitution markers are COBOL data-names prefixed by a colon (:), as shown below:

:data-name

You should always use display items inside EHTML; if you use binary data items the data displayed on the form is not human-readable.

Colons followed by a space or punctuation marker are always output as colons, and not treated as substitution markers. You can also force a colon to be output as a colon by preceding it by a backslash (\) character.

For example:

 working-storage section.
 01 acct-code    pic 9(8). 
 ...
 procedure division. 
 ...
*> First colon is followed by a space, so it is 
*> not treated as a substitution marker by 
*> EXEC HTML. Second colon is followed by a 
*> data-name, so it is treated as a 
*> substitution marker. The third colon is preceded 
*> by a backslash, so it is treated as a colon
 EXEC HTML
     Account Code: :acct-code <BR>
     \:acct-code
 END-EXEC

To qualify a substitution marker, use a period (.) between the group item data-name and the elementary item data-name. For example:

 working-storage section.
 01 customer.
  03 name         pic x(80).
  03 acct-code    pic 9(8). 
 ...
 procedure division. 
 ...
*> customer.acct-code equivalent inside EXEC HTML
*> block to acct-code of customer in COBOL source. 
 EXEC HTML
     Account Code: :customer.acct-code <BR>
 END-EXEC

You can also reference modify substitution markers:

 working-storage section.
 01 acct-code    pic 9(8). 
 ...
 procedure division. 
 ...
*> Reference modification outputs first four characters of 
*> acct-code.
 EXEC HTML
     Account Code: :acct-code(1:4) <BR>
 END-EXEC

Note: A :data-name reference is not treated as a substitution marker if it is preceded by any of a number of text strings. A list of these text strings can be found in the online Help. Click Help Topics on the Net Express Help menu, then on the Contents tab click Reference then Embedded HTML, then Substitution Markers.


7.4.1.2 EHTML Preprocessor Directives

To run the EHTML preprocessor, you need to set the following compiler directive:

preprocess(htmlpp) [preprocessor-directives] endp

All programs generated by the Internet Application Wizard start with a $SET statement to run the EHTML preprocessor:

$SET preprocess(htmlpp) endp

You can also set EHTML preprocessor directives by creating an ASCII file called htmlpp.dir, and putting it on the $COBDIR path for your Net Express system.

The EHTML preprocessor directives are documented in the online reference. Click Help Topics on the Net Express Help menu, then on the Contents tab click Reference then Embedded HTML .

7.4.2 Using DISPLAY

You can send an HTML page to a Web browser using the DISPLAY verb. The HTML page can include substitution markers for variable data to be supplied by the program. The substitution markers are not standard HTML; however the COBOL system replaces them with the variable data before sending the page to the Web browser. Each substitution marker is in one of the two following formats:

%%name%%

or

%%!s name%% 

where name is a name mapped to a COBOL data item by the IDENTIFIED BY clause on a data declaration. Use %%name%% to output the data item exactly as it is. Use %%!s name%% to strip any trailing spaces from the data item. When you are outputting plain text, the Web browser usually removes trailing spaces for you, but if you are using DISPLAY to put values into form elements, you need to strip trailing blanks using this feature.

This is the syntax to map a COBOL group data item to an output page:

level-number data-name-1 IS EXTERNAL-FORM identified by "pagefile.htm".

where:

level-number A COBOL data item level number for a group item
data-name-1 A COBOL data-name
pagefile.htm The filename of an HTML page for output

This declaration says that HTML form pagefile.htm can have data set from group item data-name-1 and its subordinate fields. To map elementary data items to form names:

sub-level-number data-name-2 picture-string IDENTIFIED BY name.

where:

sub-level-number A COBOL data item level number.
data-name-2 A COBOL data-name
picture-string A COBOL picture string. PIC X(n), PIC 9(n), and numeric edited fields are allowed. Strings longer than n characters are truncated, strings less than n characters are padded from the left with spaces
name The name of a substitution marker in the HTML page to be outputs

7.4.2.1 Example

This example shows a set of data items mapped to the fields on a form.

01 output-form is external-form identified by "outpage1.htm".
    03  name-field pic x(30) identified by "Name".
    03  phone-no   pic x(30) identified by "Phone".
    03  email      pic x(15) identified by "EmailID".

This is an example HTML page with substitution markers set up for the names above:

<HTML><BODY>
<H1>This is the output-form </H1>
<P>Dear %%Name%%,</P>
<P>You entered the following information</P>
<UL>
<LI>'phone number - <B>%%Phone%%</B></LI>
<LI>Email id - <B>%%EmailID%%</B></LI>
</UL>
</BODY></HTML>

7.5 Maintaining Application State

One of the problems with Web-based applications is maintaining application state. Each time a CGI program is run, it has no memory of what went before, or which client is using it. There are two mechanisms you can use to maintain the state of an application for each client using it:

There are two drawbacks to using either of these mechanisms on their own:

Net Express provides an extra mechanism which enables you to store all the state information on your server, where it can be accessed rapidly by server-side programs. A set of call-by-name routines in the run-time system enable a server-side program to request a unique client-id for each client which connects, and store state data for the client in an indexed file.

The diagram below shows a server-side program sending a form to a client browser, together with a client-id baked inside a cookie. The next time the client browser makes a request to the Web server, it passes back the cookie. The server-side program (which might be the same as the first one, or a different one) uses the client id to retrieve the record with the state data.



Figure 7-2: The server-side state file


Note: If you intend to store sensitive information in the state file (for example, credit card details), you should implement extra security measures such as encryption, or only providing access to the application over secure network links. A malicious user could potentially access the state records for someone else by forging a different client-id before resubmitting a form. Whether or not they see any of the actual state information depends on the design of your application, and what type of information it sends back to the Web browser.


The next three sections cover:

7.5.1 Hidden Fields

You can use hidden fields on HTML forms. On an HTML form, add one or more hidden fields to your form. These work like HTML Inputs (entry fields), except that they can't be seen by the end-user who loads your form.

When you generate a server-side program which uses the form as an input or output form, it generates COBOL data items corresponding to the hidden fields as it does for any entry field. You can store state information for your application in the hidden field when the form is output, and read it back in when the form is submitted to another server-side program.

7.5.2 Cookies

A cookie is a name/value pair sent to a Web browser along with an HTML page. You can record application state information in the cookie, and retrieve it the next time that particular client accesses a server-side program. Netscape Navigator 2.0 or later and Microsoft Internet Explorer 3.0 or later both support cookies; not all other browsers do.

The full cookies specification can be found on the Netscape site - click here.

By default, cookies are retained by the Web browser until the end-user closes the browser down. You can set an expiry date, in which case the information is stored in a cache maintained by the browser until the expiry date.

When you are designing an HTML page with Form Designer, you can create and associate a cookie with the page using the Cookies option on the Page menu. You can set the cookie's name, value, COBOL picture, expiry date, path, domain and security. You can use the domain and path attributes to share cookies between pages. When you click OK on the Cookies dialog box, Form Designer creates nearly all the code you need to set and read cookies, both server-side and client-side:

For more information about the Form Designer Cookie Editor, click Help Topics on the Help menu, then enter Cookie on the Index tab and select To add a cookie from the Topics Found dialog box.

To put a new value in the cookie while the page is being displayed, you need to add JavaScript code to the page to assign the value to the cookie. For further information on JavaScript coding see the chapter Client-side Programming.

7.5.2.1 Example Cookie

In this example you create an HTML page and associate a cookie with it. The cookie is used to keep a count of how many times the page has been accessed. The server-side program increments the counter. These instructions are not at the detailed level of "now click the OK button". They explain the overall process; detailed step-by-step instructions for the Internet Application Wizard and Net Express are available in the on-line help. If you want to get a feel for the Internet Application Wizard and Net Express before you start, run through the tutorials in Getting Started.

To create the example and set up the cookie follow these steps:

  1. Create a new project called PAGECNTR.app.

  2. Create a new HTML page selecting the blank template

  3. Create a heading then paint a form that informs the user how many times they have hit the page and also contains a submit button. The field between "page" and "times" is an input text field, which you should name "hitcounter". The form should look something like Figure 7-2.



    Figure 7-3: Cookie example

  4. Use the Cookies option on the Page menu to add a cookie with the Name cookiecounter to the page with Value set to 0 and COBOLPicture set to 9999.

  5. Click New on the File menu, and select Internet Application to start the Internet Application Wizard.

  6. Select Server Program on the first page.

  7. On the Server Program Generation page, select your HTML page in both the Input File/Form and Output Form(s) lists.

  8. Click Next, then Finish on the The End page. The Internet Application Wizard generates the server-side COBOL program and associated copy files for the form data.

  9. Open the COBOL program and find the process-business-logic section.

  10. Before the existing code, enter the following:
    add 1 to cookiecounter
    move cookiecounter to hitcounter
  11. Save the COBOL file, then rebuild the project.

  12. Run the application: if you are using Solo, just click Run on the Animate menu. You should find that each time you click Again, the hitcounter field is incremented by 1. (For more information about running applications, see the section Running the Application in the chapter Creating a New Application.)

7.5.3 The Server-side State Mechanism

The server-side state mechanism enables you to store information about the application state using a record format you define. One of the consequences of using the mechanism is that you always need a server-side program to output the first form in an application, to assign a client id at the start of the session.

If you are using a cookie to store the client id, you can set its expiry information so that state information is stored longer than the user's current session. This gives you the option of making an application persistent; the user can restart an application the following day, and be returned to where they were when last working on it. A program written for a persistent application needs to test the cookie with the client id to determine whether this is the first time it has been run or not; if the client id value is spaces, you need to allocate an id and start a new session, otherwise you need to restore the state information and display an appropriate form.


Note: The server-side state mechanism is implemented by a module called sstate. The source code is provided for sstate so that you can modify the subroutines it provides if you want to add extra functionality - encryption for example.

The source code, sstate.cbl, is in the \Program Files\MERANT\Net Express\base\demo\sstate folder. If you want to make changes to it, create a new Net Express project, and copy sstate.cbl to your new project. To get your applications to use your new sstate module, build sstate.obj and sstate.gnt versions. Copy sstate.obj to \Program Files\MERANT\Net Express\base\lib, and sstate.gnt to \Program Files\MERANT\Net Express\base\bin.

Applications generated with the Data Access Wizard all rely on sstate. You should not change the interface to sstate, or Data Access Wizard applications may fail unpredictably. The interfaces to all the sstate calls are documented in the online help. Click Help Topics on the Net Express Help menu, then from the Contents tab, click Reference, Library Routines, Library Routines by Function, and click the link to State Maintenance.


7.5.3.1 Storing and Retrieving Client State Records

The flowchart below shows the logic for using the server-side state mechanism. Click on the boxes to see more information about how you carry out each step:



MF_SET_SERVER_NAME read the client id MF_RESTORE_CLIENT_STATE process form MF_SAVE_CLIENT_STATE output form MF_ALLOCATE_CLIENT_STATE initialize a cookie
Figure 7-4: Using the server-side state mechanism

This is a summary of the information provided by the flowchart above:

  1. Specify the name of your state file.

    Call the "MF_CLIENT_STATE_FILE" routine.

  2. If this is the first time in, allocate a new client id, by calling the "MF_CLIENT_STATE_ALLOCATE" routine, then initialize a cookie or hidden control, then go to step 6.

    If this is not the first time in, read the client id from the cookie or hidden control returned by the browser and continue at step 3.

  3. Read the record for the client id.

    Call the "MF_CLIENT_STATE_RESTORE" routine.

  4. Read and process the input form, using the state information as needed.

  5. Save the client state.

    Call the "MF_CLIENT_STATE_SAVE" routine.

  6. Return the next form to the browser.

All these routines are documented in full in the on-line reference. Click Help Topics on the Net Express Help menu, then on the Contents tab click Reference, Library Routines, Library Routines by Function, and click the link to State Maintenance. The following example is the skeleton of a program showing the use of the state maintenance routines.

 working-storage section.
 ...
 01 state-filename           pic x(255) value
                             "MF-STATE-SAVE.DAT".
 01 client-length            pic xxxx comp-x.
 01 client-state.
  03 accessCount             pic 9(9).
 01 state-status             pic x comp-x.
 01 browserInput is external-form.
  03 client-id     pic x(30) identified by "clientid". *> cookie
 ...
 procedure division.
 *>  Open the client-state file.
     call "MF_CLIENT_STATE_FILE" using state-filename
 ...

 accept browserInput      *> read in the cookie with 
                          *> client id
 move length of client-state to client-length
     if client-id = spaces
*>       cookie is empty - first time in
         call "MF_CLIENT_STATE_ALLOCATE"
                    using client-id client-length state-status
         ... *> any other first time in processing
     else
*>       use client id to restore state 
         call "MF_CLIENT_STATE_RESTORE" using client-id
                                              client-state
                                              client-length
                                              state-status
     end-if
     ...
*>   Process data, and return form to client, including cookie
     ...
*>   Save client status       
     call "MF_CLIENT_STATE_SAVE" using client-id client-state
                                   client-length state-status
 

7.5.3.2 Removing Client State Records

Two routines are included for removing client state records when they are no longer required. One deletes a single record, and the other purges all records more than a certain number of days old.

To delete a single record, call "MF_CLIENT_STATE_DELETE". For example:

 working-storage section. 
 ... 
 01 state-status             pic x comp-x.
 01 client-id                pic x(30).
 01 state-filename           pic x(255) value
                             "MF-STATE-SAVE.DAT".
 
 procedure division. 
 ... 
*>  Open the client-state file.
 call "MF_CLIENT_STATE_FILE" using state-filename
 ...  
 call "MF_CLIENT_STATE_DELETE " using client-id
                                      server-status

To purge all records over a certain age, call "MF_CLIENT_STATE_PURGE". For example:

 working-storage section. 
 ... 
 01 state-status             pic x comp-x.
 01 age-in-days              pic x(4) comp-x. 
 01 state-filename           pic x(255) value
                             "MF-STATE-SAVE.DAT".
 
 procedure division. 
 ... 
*>  Open the client-state file.
 call "MF_CLIENT_STATE_FILE" using state-filename
 ...  
 move 5 to age-in-days *> remove all records more than 5 days old
 call "MF_CLIENT_STATE_PURGE " using age-in-days
                                     server-status

These routines are documented in full in the on-line reference. Click Help Topics on the Net Express Help menu, then on the Contents tab click Reference, Library Routines, Library Routines by Function, and click the link to State Maintenance.


Copyright © 2000 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.

PreviousReusing Legacy Code CGI, ISAPI and NSAPI ProgramsNext