Publish Result Sets Using Web Services and IWS
December 9, 2009 Michael Sansoterra
Note: The code accompanying this article is available for download here.
IBM i/OS V6R1 (a.k.a. 6.1) introduced a new feature called Integrated Web Services (IWS). This feature is also available by PTF on V5R4 systems. One benefit of IWS is its ability to make data and logic in high-level language programs such as RPG, COBOL and C available as a Web service.
Publishing business logic as a Web service allows clients on just about any platform (PDA, green screen, Web application, Windows client) in just about any language (Java, C#, VB.NET, VBA, etc.) to easily consume the data provided by logic in i programs and service programs. There have already been quite a few examples published on how to make RPG logic available via a Web service using IWS. I decided to “up the ante” a little over the average introductory article by creating a sample RPG Web service program that returns a variable number of customer rows based on a dynamic WHERE clause string that is passed as a parameter to the Web service.
The prerequisites for this article are:
This article will cover how to create the Web service “host” program that will receive requests for one or more customer master rows and return them to the client. My next article will cover how to access the Web service from a .NET client.
The RPG Program
Writing an RPG program for use as a Web service is nothing special. When creating one, design it as a batch program that accepts input parameters and returns output parameters. The downloadable sample RPG program CustListR is straightforward. The parameters to the program are as follows:
Listing 1–Parameters for the CustListR program.
When the program begins, it constructs an SQL SELECT statement and prepares it for execution. The query is executed and its results are fetched into a data structure array called: dsCustomers.
As evidenced by the program D-Spec, dsCustomers can hold a maximum of 500 customers. Unfortunately, RPG doesn’t currently allow developers to dynamically size arrays or multi-occurrence data structures at run time. So therefore we have to prepare for the maximum number of rows we could possibly want to return and allocate that entire memory at compile time. A single customer element in this data structure requires 117 bytes for storage. Multiplying the structure size by the number of elements gives us 117 * 500 = 58,500 bytes, which is pretty close to the 64K size limit in V5R4. (As of 6.1, the customer structure can potentially return many more rows as the data structure arrays can store up to 16MB.)
Of course, if there are only two customers being returned for a particular request we obviously don’t want to return all 58,500 bytes, which would be a waste of network bandwidth by returning a lot of blank entries! Therefore, output parameter NoCustomers will be used to identify how many rows will be returned to the caller so the program will not unnecessarily transfer all 500 entries.
One special thing to note about the RPG program is this H spec:
This PgmInfo keyword instructs the compiler to include program interface information within the program module. In other words, the program’s parameter metadata is stored internally as PCML (a specialized XML called program call markup language). As you will see, the Web services deployment wizard will use this PCML definition to deploy the Web service with as little developer intervention as possible.
Deploying the Program as a Web Service Using IWS
Now that the RPG program is complete, it can be deployed very easily to a running IWS server. This example will use a 6.1 instance, which may differ slightly from 5.4. Again, see the References at the end of this tip if you need help with this step.
For starters, point your browser to the i’s HTTP administration page. The default URL (substituting your host name) is:
If the administrative instance of the HTTP server is not normally running on your i, you’ll need to start it with the following command:
STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)
QUICK START TIP: If you don’t have an IWS server defined and if you’re adventurous, you can click the “Create Web Services Server” in the right navigation pane and let the wizard guide you through creating an IWS server instance.
When the “IBM Web Administration for i” page appears, make sure that the Manage tab is highlighted and that either “All Servers” or “Application Servers” is selected as shown in Figure 1.
If you’re running on a smaller System i box, don’t be surprised if the first visit to these management pages takes quite awhile. Some systems will return an HTTP 500 Internal Server Error while waiting for these administrative pages and their underlying internal processes to start.
Running Through the Web Services Wizard
IBM kindly gave developers a wizard to guide them through the process of deploying a program or service program as a Web service. First, select your Web services server from the server drop-down list. My IWS server for this example is called WSERVICE as shown in Figure 1.
Click the “Deploy New Service” option in the left navigation under “Web Service Wizards” and follow the wizard steps:
You can skip this screen (ok, you should probably read it once for your own edification)
Enter library and name of your program or service program. Specify program type: *PGM program, or *SRVPGM service program. In my case, I chose program (*PGM) as the program type, and entered CUSTLISTR for the program name along with my test library name.
If your program to deploy was not compiled with the Program Info (PGMINFO) keyword, then an additional request will prompt you to specify a PCML file to instruct the wizard how to describe the program’s parameters. You can create a PCML file yourself to describe your program and its parameters by following the rules for defining a PCML file.
Enter a name and description for the Web service. The service name will be included in the Web service URL that is used by clients connecting to the Web service. I entered “CustomerList” for the name and “Return a List of Customers” for the description. Please note this name is case sensitive. If you initially deploy the Web service named CustomerList then later un-install and re-deploy it as CUSTOMERLIST, the Web service URL will need to be updated for any existing Web service clients. Make sure to record this name somewhere in case the Web service needs to be uninstalled and re-deployed.
This step allows you to refine parameter usage as shown in the Figure 2.
The Web service wizard picks up the parameter information from the PCML info stored in the module (remember the explanation of the PGMINFO keyword specified on the H spec.)
Modify the parameters as shown in Figure 2. Since RPG doesn’t have any way to dictate parameter usage (input, output or input/output), the wizard defaults all parameters to input/output. For the DSCUSTOMERS parameter, the Count column should be changed from the hardcoded value of 500 to NOCUSTOMERS. As explained earlier, this will allow the Web service to only return as many customer rows as are loaded into the data structure instead of returning all 500 entries.
Use the existing user ID that the Web service runs under or choose your own user ID. For my tutorial program, I specified that the dynamic SQL data retrieval should use adopted authority (i.e., use the program owner’s authority), so in this case it is safe to use the server’s default user profile.
Add or remove entries from the library list that the Web service should use. In the sample program, the library names are hard-coded into the SQL statement so no additional libraries are required in this list. Most production services will need a library list set dynamically at run time or established in this step during the Web service deployment.
This page shows summary information about the service(s) about to be deployed. Take note of the URL to the WSDL (Web Services Description Language) document. This WSDL document is an XML document that contains information about available Web service operations and parameter information so the client can utilize the Web service correctly. If you’re deploying a service program with public functions/procedures, you can see all of these listed in the operations tab.
This is the end of the wizard!
Once you click Finish, you should return to the “Manage Web Services Server” page. Your new Web service definition may have a yellow icon next to it indicating it is being initialized.
Once the icon turns green (you may have to refresh your browser a few times), click “Manage Deployed Services.” You’ll be taken to a page that shows all the Web services defined to run on the server. Select the CustomerList Web service row (or whatever Web service you’re working with) and then choose “view definition” to see the WSDL document the wizard created for this Web service. The WSDL will communicate to the client everything it needs to know about the service, including how to exchange parameter information. Take note of the URL for this WSDL because you’ll need it when you configure your client to consume the service.
Also note that there is a “Test Service” option that can be selected. For the record, I found this browser-based testing facility a little clumsy and somewhat buggy (at least for this data structure array scenario). For me, it turned out to be easier to test my service from the .NET world. However, don’t be afraid to give it a try to see if you can get a response back from your Web service using this handy test facility.
Well, that’s it! You now have an RPG program published as a Web service that will return a set of customer rows to a client. But why bother with a Web service when you can use ODBC or JDBC to do the same job? The answer is that Web services are platform agnostic and require little or no “middleware.”
Over the years, I’ve deployed many Excel spreadsheets that access DB2 for i data. A big problem was that each of these workstations had to have System i Access and the ODBC or OLE DB provider installed and configured. Troubleshooting problems with these technologies became a headache as variations between service packs, differing versions of Windows, etc., caused problems. Further, a VPN or internal company connection was required. Finally, sometimes outsiders, such as auditors, wanted access to these spreadsheets but generally didn’t have System i Access installed.
Allowing Excel or some other application to gather the required data using a Web service call will greatly simplify client-side issues. The Excel application can call a Web service directly and a VPN connection may not be required depending on if you configure the Web service to be available over the Internet. The only drawback is that if security is a concern (and it often is) the developer will need to implement a mechanism to decide whether a certain user should be able to access the service.
After playing around with IWS, here are a few of my important observations.
1. IWS is relatively “lightweight,” requiring only a fraction of the horsepower of Websphere Application Server.
2. It’s Wizard driven and easy to use.
3. It’s free and likely to be improved.
1. Security standards are lacking. The only security implementation currently available is to use SSL.
2. Deployment is currently limited to ILE COBOL and RPG programs or service programs.
3. Lack of support for common data types such as timestamps and varying length character fields make it somewhat difficult to use. This restriction creates more work than necessary on the client side. For example, I can pass a DB2 formatted timestamp as a 26-character parameter, but it will be the client’s job to convert the character value to a timestamp equivalent. This is supposed to be accomplished without developer having to worry about such details.
4. Currently only the SOAP 1.1 protocol is supported. It would be nice to have Representational State Transfer (REST) as an option as well.
5. The auto-generated WSDL prefixes parameter names with an underscore character. This “feature” doesn’t work very well with toolkits such as the VBA-based Microsoft Office XML toolkit. This toolkit automatically generates VBA code to call a Web service (a great thing to have within Office documents),but alas, the variable names it defines are based on the WSDL document. Since VBA variable names can’t start with an underscore so the generated code causes a compilation error.
6. Parameter attribute changes will require the program to be uninstalled and re-deployed on the IWS server.
7. If you’re unhappy with the forced upper-case of the RPG program parameters, you can override them by generating a PCML file using the PGMINFO and INFOSTMF keywords on the CRTBNDRPG command. Currently the CRTSQLRPGI doesn’t support these keywords. I overcome this limitation by creating a temporary RPGLE shell program containing only parameters and then compile it to simply generate the PCML.
Here’s an example:
PGMINFO(*PCML *ALL) INFOSTMF('/myPCML/CustListR.pcml')
You also have the option of changing the PCML file to suit your needs, or instructing step 2 of the wizard to use the PCML file.
Integrated Web Services provides an excellent entry-level, easy-to-use option that will allow i shops to start enabling their own service oriented architecture. The IT shop of the future is likely to contain many loosely coupled, platform agnostic services that will be accessed via Web services. IWS is a great way to allow ILE programs to enter this world. In the next article in this series, I’ll demonstrate how a .NET client can consume the sample Web service created here.