Skip to main content

 
IBM Power Systems software  >  IBM i  > Software  > 

Net.Data for i5/OS

  
Overview News Library Education Support
Persistent Net.Data

Today, Net.Data treats each macro invocation as one complete transaction. This means that after each response is sent to the browser, databases are committed, resources are released, and everything is set to an initial state. The next invocation of the same macro results in re-establishing the state of the application based on information passed into the macro as form data or information in the macro itself. There is no capability to save macro variables across invocations, to rollback database changes without explicitly undoing the changes made, or to treat database changes across multiple browser sessions as one complete transaction.

HTTP Server Persistent CGI Model
In version 4, release 3 (V4R3) of i5/OS, the IBM HTTP Server for System i has added support for a persistent CGI model. The persistent CGI model attempts to capture the advantages of both the CGI model and the server API model, providing process isolation as well as program persistence without the overhead of an entirely new protocol.

It's easiest to view the persistent CGI model as an extension of the existing CGI model. A persistent CGI program runs as a child process of the HTTP server, receives input through standard input and environment variables and provides data through standard output. The difference is that after the output is returned to the HTTP server, the program (and process) does not have to terminate. Instead it can remain active waiting for a response from the client. State information can be maintained and transactions can be left open.

The server must be notified that this process wishes to remain persistent. Once notified, the server must remove the process from it's "available process" list of server jobs and maintain the information necessary to re-invoke that particular process when requested. This information will be sent to the server by the program via a CGI header. The CGI header is a number of text statements returned by the CGI program prior to the body of the CGI output. Typical CGI header statements include Content-Type, Location, and Status. These headers are parsed by the HTTP server before returning the information to the browser. A new header, "Accept-URL" will be added to describe which URL or URLs will be accepted by this CGI program in subsequent requests.

The characteristics of persistent CGI programs are very similar to those of standard CGI programs with the following exceptions:

  • They run in a pseudo-connection-oriented environment. The connection between the CGI program and the HTTP server is persistent, but the connection between the browser and the HTTP server is still connectionless.
  • They can have long running transactions. Since a single CGI process can span multiple browser requests, transactions can be left open and committed or rolled-back as appropriate based on subsequent browser requests or error conditions.
  • Since a persistent CGI process can remain active for potentially long periods of time, it can consume more system resources. Care must be taken in the management of those resources.
  • Portability is reduced due to the support required in the HTTP server.

Net.Data Persistent Macro Model
By taking advantage of the HTTP server persistent CGI model, Net.Data can come closer to a business application engine and provide real transaction processing. Application developers can build their application with multiple sections within a macro or multiple macros acting as one transaction. Also, they no longer need to pass information (such as user login id) between macro invocations as hidden variables because that information is persistent throughout a transaction. Most importantly, the application has the capability to rollback all the work if the user decides to cancel out while in the middle of a transaction.

The persistent macro model provides interfaces to perform the following tasks:

  • Start a transaction
  • Continue a transaction
  • End a transaction
  • Scope data in a transaction
  • Commit and rollback changes in a transaction

Starting a Transaction
You start a transaction by indicating to Net.Data that a macro is persistent. You can do this in one of two ways:

  1. Call the DTW_STATIC() built-in function.
  2. Define a variable with the STATIC attribute.

Whichever method you use, you must place it in your macro before any output is sent to the browser. This is because Net.Data must send a special HTTP header to the Web server to tell it we are using persistent CGI support, and Net.Data decides what header to send when it sends its first output to the browser.

The DTW_STATIC() function's sole purpose is to tell Net.Data that the current macro is persistent. Typically, it will be the first line of a persistent macro. You may optionally specify a timeout value on the function call. This value is the number of seconds the HTTP server should wait for a response from the browser before ending the transaction. Here's a sample:

@DTW_STATIC("60")
%DEFINE {
  var1 = "val1"
  var2 = "val2"
  var3 = "val3"
%}

%HTML(INPUT) {
 ...
%}

...

In this example, a timeout value of 60 seconds is specified for this transaction. If a response is not received within 60 seconds from the browser, the HTTP server will end the transaction. This does not affect the current page on the browser. However, the next page which would have been part of the transaction will now be a new transaction.

The other way to make a macro persistent is to define a variable as STATIC. This is done using the following syntax:

%DEFINE(STATIC) var1 = "val1"

A statically defined variable will keep its value throughout a transaction, which could span multiple Net.Data invocations.

Continuing a Transaction
You continue a transaction by indicating to Net.Data what subsequent macro invocations can be a part of your transaction. This is done by specifying a "handle" that must be a part of the URL for those subsequent invocations in the transaction.

You tell Net.Data what the handle is by calling the DTW_ACCEPT() built-in function. This function takes a single input parameter specifying the handle, and again, must be specified before any output is sent to the browser. Typically, it's the first call inside an HTML block. Net.Data also provides a built-in function that will generate a unique handle. It is the DTW_RTVHANDLE() function. It takes a single output parameter into which it will place the handle. Here's a sample using the DTW_RTVHANDLE() and DTW_ACCEPT() calls:

@DTW_STATIC()
 ...

%DEFINE handle = ""
@DTW_RTVHANDLE(handle)
 ...

%HTML(SECTION1){
@DTW_ACCEPT(handle)
 ...
%}

You can call DTW_ACCEPT() outside of any HTML block, in which case it will apply to all HTML blocks within the macro. If you call it as the first thing inside an HTML block, you must be careful that there is no whitespace between the line the %HTML directive is specified on and the DTW_ACCEPT() call itself. This is because Net.Data will consider the whitespace as text to send to the browser, and will then issue an error since the DTW_ACCEPT() call was not found before data was sent to the browser.

The handle can be any valid character string. However, the DTW_RTVHANDLE() call provides a measure of security in that nobody else will know your handle, and thus cannot invoke a macro which would run in your transaction.

Once you have generated a handle and called the DTW_ACCEPT() function, only URLs with that handle can run in your transaction. Typically you will provide anchor references to these URLs or specify the URL on a form action tag. The handle must immediately follow the cgi program name in the URL. In Net.Data's case, the program name is generally mapped to db2www, so a URL in your macro might look like this:

http://www.mycompany.com/cgi-bin/db2www/$(handle)/macro/section
The following sample shows a typical HTML block with links to other macro invocations that will run in the same transaction:
@DTW_STATIC()
 ...
%define handle = ""
@DTW_RTVHANDLE(handle)

%html(report) {
@DTW_ACCEPT(handle)
 ...
continue
quit
%}

Ending a Transaction
You end a transaction by indicating to Net.Data that you no longer want your macro to be persistent. This is done using the DTW_TERMINATE() built-in function. Like the DTW_ACCEPT() function, this is typically specified as the first thing in an HTML block. Here's an example:

@DTW_STATIC()
 ...
%define handle = ""
@DTW_RTVHANDLE(handle)

%html(report) {
 ...
%}
 
 ...

%html(quit) {
@DTW_TERMINATE()
 ...
%}

Scoping Data in a Transaction
You can decide what scope you want a variable to have in a transaction by specifying the scope as an attribute to the %DEFINE statement. An attribute of STATIC indicates that the variable will have transaction scope, meaning the value of the variable will be saved across all invocations in a transaction. An attribute of TRANSIENT indicates that the variable will have single invocation scope, meaning the value of the variable will be reinitialized on each invocation. This is the default action for non-persistent macros.

In a macro in which DTW_STATIC() is called, all variables following the DTW_STATIC() call that are not explicitly defined as TRANSIENT are STATIC. All variables preceding the DTW_STATIC() call that are not explicitly defined as STATIC are TRANSIENT.

Commits and Rollbacks in a Transaction
In a non-persistent macro, a commit or rollback is done implicitly by Net.Data at the end of the macro invocation based on the success or failure of the invocation. With persistent macros, the commit or rollback is now done at the end of the transaction. However, because a transaction can span many macro invocations, a user may want to commit or rollback changes incrementally within the transaction. This functionality is provided by the DTW_COMMIT() and DTW_ROLLBACK() built-in functions.

These functions do not take any parameters and basically just do what their names imply. The DTW_COMMIT() function will commit all changes pending in the transaction, and the DTW_ROLLBACK() function will rollback all changes pending in the transaction.


Transaction example
Here's a simple macro with multiple HTML blocks that run in a single transaction:

0001.00 @dtw_static()
0002.00 %define a = "0"
0003.00 %define(transient) b = "0"
0004.00 %define handle = ""
0005.00 @dtw_rtvhandle(handle)
0006.00
0007.00 %html(report) {
0008.00 @dtw_accept(handle)
0009.00 a = $(a)
0010.00 b = $(b)
0011.00 @dtw_add(a, "2", a) 0012.00 @dtw_add(b, "2", b) 0013.00 0014.00 click here to continue
0015.00 0016.00 click here to quit
0017.00 %} 0018.00 0019.00 %html(report2) { 0020.00 @dtw_accept(handle) 0021.00 a = $(a)
0022.00 b = $(b)
0023.00 @dtw_add(a, "2", a) 0024.00 @dtw_add(b, "2", b) 0025.00 0026.00 click here to continue
0027.00 0028.00 click here to quit
0029.00 %} 0030.00 0031.00 %html(report3) { 0032.00 @dtw_accept(handle) 0033.00 a = $(a)
0034.00 b = $(b)
0035.00 @dtw_add(a, "2", a) 0036.00 @dtw_add(b, "2", b) 0037.00 0038.00 click here to quit
0039.00 %} 0040.00 0041.00 %html(quit) { 0042.00 @dtw_terminate() 0043.00 done 0044.00 %}

Assuming the first call is to the report section, Net.Data does the following:

  • Calls the DTW_STATIC() function, which indicates this is a persistent macro
  • Creates variable a as a STATIC variable, since the default for persistent macros is STATIC
  • Creates variable b as a TRANSIENT variable, since it was explicitly defined as such
  • Calls DTW_RTVHANDLE(), which generates a handle and puts it in the variable handle.
  • Calls DTW_ACCEPT(), which tells Net.Data what this transaction's handle is
  • Finds some output to send to the browser, which causes Net.Data to send the HTTP header to the server indicating we have started a transaction
  • Puts out the HTML page. The variables a and b both have a value of 0.

After the first page is output, the user can choose to either continue with the transaction or quit. If he clicks on continue, the URL

/cgi-bin/db2www/$(handle)/qsys.lib/mylib.lib/macros.file/pcgi1.mbr/report2
is invoked. The HTTP server will recognize the handle as the one specified by Net.Data in the HTTP header, and will invoke Net.Data as a persistent CGI program, which means the macro invocation will be part of the current transaction. In the report2 invocation, Net.Data does the following:
  • Calls the DTW_STATIC() function, which indicates this is a persistent macro
  • Sees that variable a is a STATIC variable, so it keeps the current value of a rather than reinitializing it to 0
  • Sees that variable b is a TRANSIENT variable, so it creates a new instance of variable b and initializes it to 0
  • Calls DTW_RTVHANDLE(), which generates a handle and puts it in the variable handle.
  • Calls DTW_ACCEPT(), which tells Net.Data what this transaction's handle is
  • Finds some output to send to the browser, which causes Net.Data to send the HTTP header to the server indicating we are continuing a transaction
  • Puts out the HTML page. Variable a will have a value of 2 and variable b will have a value of 0. Variable a's value is saved from the previous invocation because it is a static variable. Variable b is not.

After the second page is output, the user can choose to either continue with the transaction or quit. If he clicks on quit, the URL

/cgi-bin/db2www/$(handle)/qsys.lib/mylib.lib/macros.file/pcgi1.mbr/quit
is invoked. The HTTP server will recognize the handle as the one specified by Net.Data in the HTTP header, and will invoke Net.Data as a persistent CGI program, which means the macro invocation will be part of the current transaction. In the quit invocation, Net.Data does the following:
  • Calls the DTW_STATIC() function, which indicates this is a persistent macro
  • Sees that variable a is a STATIC variable, so it keeps the current value of a rather than reinitializing it to 0
  • Sees that variable b is a TRANSIENT variable, so it creates a new instance of variable b and initializes it to 0
  • Calls DTW_RTVHANDLE(), which generates a handle and puts it in the variable handle.
  • Calls DTW_TERMINATE(), which tells Net.Data that this is the last invocation in this transaction
  • Finds some output to send to the browser, which causes Net.Data to send the HTTP header to the server indicating we are ending a transaction
  • Puts out the HTML page. Variable a will have a value of 4 and variable b will have a value of 0.
  • Cleans up. Since the DTW_TERMINATE() call was executed, Net.Data cleans up all variables and other resources scoped to the transaction.