In the October 2006 issue of My i - .NET, I described how you can use the Client Access Data Queues ActiveX controls with Windows Forms applications. The great virtue of using the controls is their simplicity: you have only to add a control to a form and work with a few properties and methods to have a functional data queues application.
However, those controls would not be of much use if you want to develop an ASP.NET web application or a server application that does not have a Windows form user interface. The good news is that you can still employ data queues with those types of applications by using the data queues API. The bad news is that there are more tasks that you need to do to work with the API.
Nevertheless, the technique is still simple to understand and implement. In this month's example I'll show you a data queues client application that works with an RPG server program. The client application sends its request to the server on one data queue and receives responses from the RPG program on another. The data queues used in my example are not keyed queues although that technique is supported by the API.
The data queues API has been available for Windows programming since the early days of IBM's PC Support product. The API remains virtually unchanged from the version that was introduced with Client Access Express (back in the Windows 95 days). So if you have any previous experience with the COM versions of Client Access APIs, you'll be right at home with the .NET version because there is no version of the data queues API specifically coded for .NET. In actual practice, you probably won't know that you're working with the older COM type of component. I can't imagine that if IBM provides a .NET version that there would be any differences in how you program it.
The data queues API and other APIs that are of interest (remote command, program call, and others) are in the cwbx.dll file that is installed as part of iSeries Access for Windows. To work with the DLL in Visual Studio, right-click on your project and add a reference. On the Add Reference dialog (Figure 1 [2]), select the COM tab and then scroll down until you locate the IBM AS/400 iSeries Access for Windows ActiveX Object Library, as shown in the figure. You'll also find documentation for the API in the IBM iSeries Access for Windows Programmer's Toolkit, which is optionally installed on your PC along with the iSeries Access for Windows product.
The code available for this article includes the Visual Basic source code (Module1.vb [3]) and an ILE RPG program (DQTESTER.rpgle [4]). The RPG program uses a logical file (QCUSTCDTL.lf [5]) that is built over the QIWS/QCUSTCDT file. Rather than describe the RPG program, I'm going to assume that you are able to create the logical file and compile the RPG program. If you're not familiar with the QSNDDTAQ and QRCVDTAQ APIs on the System i, you can find information about those APIs in the IBM System i Information Center.
Before you can run the Visual Basic program, you need to perform the following steps:
Now examine the code in the Visual Basic program. Before running the program, you need to change the constants shown in Section A near the top of the program source file. You need to set your System i TCP/IP host name, the name of the SEND_DTAQ_LIBRARY, and the RCV_DTAQ_NAME and RCV_DTAQ_LIBRARY to correspond with the data queue and library names that you configured above. After you've made those changes, you can run the program.
The program uses Console input and output. Figure 2 [6] shows the initial prompts that you'll see. For the first test, enter the request value *GETCUST and then enter one of the customer numbers that is in the QCUSTCDT file (you can use the DSPPFM command to view the contents of the file to see the customer numbers). After you enter a customer number, you'll see the field data for that customer's record, as shown in Figure 3 [7].
Now restart the program and enter *GETLIST as the prompt value. You'll see a listing of customer data for all customers in the file, as shown in Figure 4 [8].
To use the data queue APIs in the program, I started by coding the Imports statement shown at the top of the Visual Basic source file. That gives me the ability to use classes in the cwbx namespace (in the cwbx.dll) without needing to specify the namespace on each use of a class.
Section B includes constants and enumerations that are used in the program. Although it probably looks really tedious and cumbersome to have all that code, understand that you need to exactly match the code in the Visual Basic program with the code in the RPG program.
The send-and-receive data queues move messages between your programs. The messages are in the form of fixed-length strings. The most convenient way to handle the fixed-length strings is to treat them as data structures. You can see the data structure (named "Data") in the RPG program.
The other important features that need to match up exactly are the values you use to send requests to the RPG program and the values that the RPG program returns to indicate the type of response. Essentially, you are coding something similar to an old internally described file in which you use record identifying codes to let you know what type of record you're working with. I am warning you: if you don't match up the data structures and the request/response codes, you will spend many unhappy hours debugging. By moving all the relevant factors to constants, it is still possible to make mistakes in the definitions.
The reason to favor constants as opposed to coding the values in-line in the program is that if there is an error in the definition, it only needs to be corrected in one place. For example, if I mistype the REQUEST_GETCUST value as *GETCST instead of the value *GETCUST that the RPG program expects, I only need to correct it in the constant. If I had used the literal value instead of the constant, I would need to carefully check each occurrence of the literal if I used it more than once.
The code in Section C defines two converter objects that are in cwbx. The converters are needed to convert from the System i EBCDIC and numeric data types to data types that can be used in Windows programs. In this example, I use only a string and a zoned converter. There are also converters for packed, short and long numeric data types.
Section D defines an AS400System object (the AS/400 name will never die; it is in too many APIs).
Section E defines a Structure object that is the Windows equivalent of the RPG data structure. The subfields in the structure are listed in the same order that the fields occur in the RPG data structure. The length of each subfield is specified but not its data type or decimal positions. The definition shown in Section E creates a structure of contiguous subfields. I did not examine the Structure class extensively to determine if it is possible to define overlapping subfields.
Section F prompts for the request type. Note that in the second If condition in this section, the value of the customer number to retrieve is converted with the StrCvt object and assigned to the CUSNUM data structure subfield.
In Section G, the DQWrite data queue is defined. That data queue is used to send the request from the Visual Basic program to the RPG program. You set the System, QueueName, and LibraryName properties to identify the name of the data queue and where it is located. After setting those properties, the request parameter value is set along with the name of the receive data queue that the Visual Basic program will receive the responses from. Finally, the Write method is used to write the data structure as an array of bytes. The message is on its way to the RPG program.
Section H is where the responses from the RPG program are processed. The section starts by defining the DQRead data queue. It then uses the Read method with the parameter value of DQ_WAIT_FOREVER (a value of -1). The use of the wait parameter on this API is the same as its use on the System i QRCVDTAQ API. The result of the read is an array of bytes, which is assigned to the DSData structure.
After receiving a data queue entry, the Visual Basic program needs to determine what type of response it received. If the request was for an individual customer, the response type is RECEIVE_TYPE_CUSTOMER. If a customer list was requested, the response types will be a sequence of zero to many RECEIVE_TYPE_CUSTLIST responses (one response per customer record), followed by a RECEIVE_TYPE_CUSTEND response (an "end of file" marker). After receiving a response, the structure is passed to the ProcessCustomer subroutine.
The ProcessCustomer subroutine calls the overloaded convenience function ParseStructureField to parse a string or zoned subfield from the data structure. After parsing out the subfield value, the value is written to the console.
The other subroutines and functions in the program are not significant in terms of working with data queues.
In my testing, I discovered one error. You can see it in the ProcessCustomer subroutine. The mistake occurs when I try to parse the zoned fields that have two decimal positions (BALDUE and CDTDUE).
When I ran my test, I noticed that I was not getting a value for BALDUE although I was seeing a value for CDTDUE. When I looked into the database file, there was a value for BALDUE. Because the error seems to be that the first instance of the field cannot be retrieved, I simply added a duplicate retrieval of the BALDUE field to the code. I am using iSeries Access for Windows V5R3M0 Service Pack SI24723. If you are using another version of the product or a different Service Pack, you might not get the same error.
You now have a complete example of a data queue API application that you can use with any type of .NET program. Data queues are a great technique to use with client/server programming. You can easily develop RPG server programs that provide a lot of functionality and pair them with Windows programs to provide the user interface.
Craig Pelkie has worked as a programmer with IBM midrange computers for many years. He has also written and lectured extensively on AS/400 and System i technologies, including client/server programming, Client Access, Java WebSphere, .NET applications for the System i, and web development. You can reach him at craig@web400.com [9].
Links:
[1] http://systeminetwork.com/author/craig-pelkie
[2] http://pentontech.com/IBMContent/Images/article/56565_50543_fig01.jpg
[3] http://pentontech.com/IBMContent/Documents/article/56565_550_Module1.vb.txt
[4] http://pentontech.com/IBMContent/Documents/article/56565_551_dqtester.rpgle.txt
[5] http://pentontech.com/IBMContent/Documents/article/56565_552_qcustcdtl.lf.txt
[6] http://pentontech.com/IBMContent/Images/article/56565_50544_fig02.jpg
[7] http://pentontech.com/IBMContent/Images/article/56565_50545_fig03.jpg
[8] http://pentontech.com/IBMContent/Images/article/56565_50546_fig04.jpg
[9] mailto:craig@web400.com