Sometimes you just need to get it done quickly, whatever it might be. This certainly applies to the demands of IT development, whether its a new development, an enhancement, or an ever-dreaded maintenance task. For many of your applications, youve developed libraries of well-tested routines and code snippets that make the job easier and faster. These libraries are what economists identify as an increase in worker productivity.
But what about Web application development? It takes years of development and development experience to build these libraries, and Web development is new to many of us. One alternative is to use a tool that supports rapid development yet minimizes the compromises such tools often bring along with them. One such tool is Net.Data.
Net.Data started life in IBMs DB2 UDB labs as an offering known as DB2WWW. In the early days of the Web and HTML, it was a response to the need to dynamically publish data residing in a production database to a Web page quickly and easily. A macro or a script (choose your desired word) could be developed in a text editor and saved to a directory, and the DB2WWW interpreter would execute the saved instructions interactively from within the Web server. Finally, instant gratification for the developer. At the time, the primary alternative was to write a custom Common Gateway Interface (CGI) program for each data retrieval task.
Over time, new function was added to DB2WWW, andas with all good things IBMit was renamed Net.Data. It is now a strategic part of all the DB2 UDB implementations, including the AS/400, and is provided with the database at no additional charge. Getting Net.Data to operate generally requires no more than a few entries in an HTTP server configuration.
Net.Data provides essentially all of the capability found in any other programming language or environment. To accomplish this, Net.Data developed its own language and structure. The purpose of this article is to introduce you to that structure, and see how complex implementations can be developed from a few relatively simple components. Over time Ive found development easier in a new language or environment if I can first understand the basic parts of the language and how these parts fit together.
Web.Now
For the purposes of this article I will refer to a file containing Net.Data code as a macro. Calling the code a script or a program is just as validthough IBMs documentation uses the word macroso I will use it for consistency.
Begin with a Block
The primary language construct in Net.Data is known as the block. Blocks group common pieces of function together and allow the developer control over what occurs and when it occurs inside the macro. Blocks are very familiar to experienced programmers. For example, a block in CL is defined by the Do/End keyword combination and is defined by the open brace ({) and the close brace (}) characters in C or C++. Net.Data blocks begin with the percent (%) character, followed by an identification of what type of block that it is, and finally the { character. All Net.Data blocks end with the %} character combination.
The simplest possible Net.Data macro must contain at least one block, and that block must be an HTML block. The following line of code, for instance, is an example of the famous Hello World example in Net.Data:
%HTML(HELLO){
Hello World
%}
As I noted, the block begins with the % character. Next, the type of block is identified (in this case HTML), the block is given a name inside the parentheses, and the beginning is finished up with the { character. The simple HTML producing Hello World should be easy to recognize.
The purpose of an HTML block is to output something to the requesting browser, typically HTML or text. The output approach Net.Data takes is to send anything it does not recognize as a part of the language to the browser. If the unrecognized content happens to be valid HTML, the browser should behave as expected.
Multiple HTML sections are allowed within a single macro file. One distinct advantage to this feature is an ability to produce and maintain an entire Web site, or a significant portion of it, from within a single source file. Another advantage is the ability to share other code in the macro file between different Web pages on a site. The result will be a more-consistent-looking, easier-to-maintain site.
Net.Data parses macros from the beginning to the end without regard for line breaks. A block can be nested within another block all on the same line in the source file, if desired; however, line breaks do add to the readability of any piece of code and can be added anywhere within the block with just a few exceptions inside the beginning and ending character combinations.
All good developers provide lots of good comments in their code, right? Net.Data provides for comments again by using the block construct. Any block that begins simply with the %{ character combination is treated as a comment. As with all blocks, the comment ends with the %} combination.
Data Is Always Changing
A programming environment wouldnt be much good without the ability to support variable data, and Net.Data is no exception. Its support for variables is similar to the support in many other macro facilities and interpretive languages in that all variable data is stored internally as a character string and is converted to numeric or other formats if a particular operation demands it.
Variable names must begin with a letter or the underscore (_) character and can contain any character after the first. Variable names can be very long, with the actual limit depending on the operating system on which Net.Data is running. Variable names in Net.Data are case sensitive. Be sure to check the source code carefully for case or spelling differences if a reference to a variable does not behave as expected.
Variables either are created explicitly by using a %DEFINE block or can be defined implicitly by assigning a value to a variable name inside the DTW_ASSIGN built-in function. Implicit creation is similar to creating a new variable right in the result field of an RPG C spec, whereas explicit creation is similar to defining the variable in the RPG IV D spec. The debate over implicit vs. explicit variable creation has gone on for a long time, but likely you will want to plan your project to include explicit creation.
One difficulty related to Net.Datas variable creation behavior is that if you misspell or fail to match the case of an explicitly defined variable within a DTW_ASSIGN function, you will end up with a new variable that contains the desired value. The value of the variable you were trying to change will not have been altered, which just means you need to be careful.
HTML forms are a big part of any Web application. Fields, defined as part of a form within a Net.Data macro, automatically become variables and are available for use elsewhere in the macro.
Web server software platforms tend to use operating system environment variables extensively, making them very important in Web applications. For example, the user ID of the individual using the application may be available in an environment variable. Net.Data provides special, automatic support for querying and updating environment variables. If the macro variable is created in a %DEFINE block, with the same name as the environment variable and assigned the reserved value %ENVVAR, Net.Data will populate the variable with the value from the environment each time the variable is accessed. Net.Data will also update the value in the environment when it is changed from within the macro.
Another special type of variable exists within Net.Data, particularly to support its role in retrieving data from database tablesthat being the %TABLE variable type. A Net.Data table is similar to an array but really is more easily compared to a database table, except that the Net.Data table is located in memory. %TABLE variables have a variable number of rows, each of which contains columns of data. A limited set of Net.Data functions will process %TABLE variables.
Variables within Net.Data have scope, much as they do in other language environments. If a variable is defined at the beginning of the macro, outside of any operational block, it will have global scope. That is, the variable and its value will be available anywhere within the macro. A variable defined inside a block, such as an HTML block, will only be available within that block and will not be visible to other parts of the macro. In all cases, the variable must be defined before it is first used because Net.Data is interpreted.
String handling in Web applications is important, and often the contents of a variable must be inserted simply as text. Other languages require the use of some sort of output function or printing of the value before it can be visible. Net.Data will output the contents of any variable, except %TABLE variables, simply by enclosing the variable in parentheses and prefacing it with the dollar ($) character. This sounds more complicated than it is.
Going with the Flow
Now that you know Net.Data has variables and has a distinct organization within the macro, you need to know how to control the flow of the program. The primary flow of control operations in any language really gets down to either executing logic based on the satisfaction of some condition or executing some logic for a controlled number of times (a loop).
Conditional expressions in Net.Data are constructed using %IF / %ELSE / %ENDIF statements. They break the rules of a block somewhat in that the { characters are not used. If the condition (in parentheses) following the %IF statement is true, the statements following the condition are executed. Otherwise the statements following the %ELSE reserved word are executed up to the %ENDIF statement.
The available conditional operators and the rules for the conditional test are similar to those in the C programming language. Two equal signs (==) are used for equivalency, and the exclamation point (!) represents not (i.e., != would be not equal).
%ELIF, a special version of %ELSE, is available that combines the capability of a %ELSE followed immediately by another %IF. %ELIF makes nested if logic much simpler to construct.
Loops in Net.Data are constructed with the %WHILE block. %WHILE contains a condition that is tested at the beginning of the loop, and all of the statements within the loop are executed if the condition is true. Execution passes to the statements following the end of %WHILE block if the condition is not true. Although some of the looping construct variants like FOR/NEXT and DO UNTIL that you often expect in a programming language dont seem to be available, they all can be simulated with logic within a %WHILE block.
Functional Enhancement
The real work in most programming environments happens inside functions, and Net.Data is no different. Several types of functions are available, including user-defined functions, functions related to language environments, the mechanism Net.Data uses to connect to databases and other programming environments, and built-in functions.
User-defined functions give you a way to consolidate a set of statements that may be executed from more than one place within the macro. User-defined functions can accept a set of parameters and can contain any statements, blocks, or function calls necessary to get the job done. One interesting issue, though, is that, due to the fact that execution of Net.Data is interpreted, not compiled, a user-defined function must be defined in the source file before it is called.
Language environment functions are typically used to insert SQL statements. Each SQL statement needs a function defined before it can be executed and can either return query results as HTML directly in a Web page or in a %TABLE variable for processing elsewhere in the macro.
Both user-defined and language environment functions have a couple of special blocks within them. The first is a %MESSAGE block. This block allows the delivery of custom messages depending on particular return codes. In the case of SQL, the code is the SQLCODE associated with execution of the statement.
The other special block is %REPORT, and its subordinate block, %ROW. The statements inside %ROW execute once for each row returned from the execution of an SQL statement. Inside a user-defined function, the statements within the %ROW block execute once for each row in a %TABLE variable. Statements in the %REPORT block, outside of %ROW, execute once for each call of the function, either before or after the %ROW statements depending on their position relative to the %ROW block.
Built-in functions often make or break a development environment. Net.Data has a bunch of functions available, and they can take care of necessary programming needs like string handling, date, time, math, and interfaces to operating system programs.
Many of the built-in functions are supplied in two separate forms. The first form returns the result of the function as a parameter. The return value of the function will be the return code resulting from the execution.
The other built-in function form returns the result directly from the function and is identified with the characters DTW_r preceding the function name instead of DTW_. This form is useful when the results of a function are to be a parameter to another function. The first function can be specified within the call to the second, saving a couple of lines of code.
Functions are executed simply by prefacing the name of the function with the at (@) character.
All the Functionality in One Place
Figure 1 is reasonably self-explanatory and demonstrates a number of the features of the Net.Data language Ive described. It can be executed on any AS/400 that has Net.Data configured. Configuring Net.Data is a relatively simple task, and IBM provides a good guide at www.as400.ibm.com/products/netdata/docs/tips.htm.
The file contains two HTML sections, either of which is executed by specifying the section name at the end of the macro URL. For example, on my AS/400 the Examples HTML section is executed by using the URL 10.1.12.197/cgi- bin/db2www/pub/www/anatomy.txt/ examples. Figure 2 is the Web page the section produces.
In the end, is it better to develop a Web site with a Net.Data macro, or should you write programs? The answer is almost always the same: It depends. A Net.Data macro likely wont be the highest performance solution, but it sure can be a quick way to get the job done. In my experience the ability to make small changes and immediately see the result is a tremendous benefit. Appropriate attention to database and SQL tuning, along with the appropriate use of certain Net.Data functions, can result in good performance, while getting the site up quickly. Ultimately a mix of macros and native programs is likely the best way to develop a site.
Give Net.Data a try. I firmly believe you will find it a very useful tool for taking your organization to the Web.
REFERENCES AND RELATED MATERIALS
AS/400 Net.Data home page: www.as400.ibm.com/netdata
AS/400 Net.Data Tips and Techniques: www.as400.ibm.com/products/netdata/docs/tips.htm
Net.Data documentation: www.as400.ibm.com/products/netdata/docs/doc.htm
%HTML(Basic){
A basic HTML block is named and is selected on the URL used to access the macro.
As with HTML, line breaks can be added for source readability but are ingnored
as the macro is processed.
%}
%{Comments are enclosed in a block without any identifying type.%}
%{A variable defined outside of any other block will be global in scope.%}
%DEFINE{ A_Variable = variable data %}
%{Accessing environment variables is relatively easy.%}
%DEFINE{ REMOTE_ADDR = %ENVVAR %}
%{Functions must be defined outside of an HTML block and must be defined in the source
file before they are used. See the Examples HTML section for how this is utilized%}
%FUNCTION(DTW_SQL) query_columns (IN TABLE_NAME) {
SELECT COLUMN_NAME, DATA_TYPE, LENGTH FROM QSYS2.SYSCOLUMNS WHERE TBNAME=$(Table_name)
%MESSAGE{
100 :
No columns found for table $(Table_name)
: exit
default :
An SQL error occurred. Return code was $(RETURN_CODE)
:
exit
%}
%REPORT{
The following columns can be accessed within the $(Table_name) table:
%ROW{
Column $(V1) is of type $(V2) and has a length of $(V3)
%}
%}
%}
%HTML(Examples){
An Anatomy of the Net.Data Language
%{Variables are case sensitive. The DTW_ASSIGN built-in function will create a new variable if it doesnt
exist.
Since the variable is defined inside a block its scope will be limited to the block.%}
@DTW_ASSIGN(A_variable,the other variable data)
The contents of a variable can be accessed by enclosing the variable name in parentheses
and preceding it with the $ character. But be careful of the case sensitivity issue because the $(A_Variable) could be $(A_variable).
Accessing environment variables is relatively easy. For example, the remote
address accessing this page is $(REMOTE_ADDR).
@DTW_ASSIGN(The_question, Yes)
%IF(The_question == Yes)
Conditional expressions use an IF statement.
%ENDIF
@DTW_ASSIGN(The_question, No)
%IF(The_question == Yes)
This text wont display.
%ELSE
This text will display since the value of the variable changed.
%ENDIF
%IF(The_question == Yes)
Nothing happens here.
%ELIF(The_question == No) The ELIF statement helps to streamline coding of nested IF conditions.
%ENDIF
@DTW_ASSIGN(Loop_counter, 0)
%WHILE(Loop_counter < 5){
Loops are important in any programming language.
%{The program needs to take care of the loop condition itself
so a built-in math function is used to increment the counter.%}
@DTW_ADD(Loop_counter, 1, Loop_counter)
%}
A function is called simply by prefacing its name with the @ character.
@DTW_ASSIGN(Table_name, SYSTABLES)
@query_columns(Table_name)
There are only a few rules about how a Net.Data macro must be organized. Past coding examples
have implied that order may be more important than it is or that certain elements are
absolutely required. Very simple macros will operate properly and with the capabilities
of the Net.Data language extensive, dynamic Web sites can be developed quickly and easily.
%}
Figure 1: It is relatively easy to demonstrate all of the essential elements of the Net.Data language.
Figure 2: A simple Web page is what the Examples HTML section of Listing 2 will produce.
LATEST COMMENTS
MC Press Online