IBM i > DEVELOPER > RPG

EGL and XMLService: Hand, Meet Glove

EGL and XMLService: Hand, Meet Glove

When I read the article “XMLSERVICE Offers New Life for RPG Programs” my first thought was, “Wow! That is really powerful stuff!” Not only does XMLService support regular program calls but it supports service program procedure calls better than anything else I have seen—and it has a whole host of other features.

My second thought was, “That should be dead simple to leverage with EGL.” Support for XML-based services is built into EGL and, after installing XMLService, I had an example running using an EGL program to call an RPG program in just a couple minutes.

Let’s look at just how easy it is to bring EGL and XMLService together. I’m using the just-released open-source version of EGL and related tools. You can find this software at the Eclipse EGL Development Tools (EDT) project site. I’ve also used XMLService with IBM’s fee-based Rational Business Developer (RBD) product. The RBD code is slightly different than that shown here due to syntax changes in EGL introduced by EDT. Version 0.8M1 of EDT includes a patch that’s required for this example to work properly. Instructions for installing this “milestone” release are on the EDT download page.

The examples that follow use EGL generated to a rich Web client (JavaScript) but, as is the nature of EGL, I didn’t have to actually code any JavaScript or learn any third-party frameworks to make these examples work. I also didn’t have to establish any servers beyond a simple Apache Web server running the XMLService interface. The interface between EGL and XMLService is completely client-side stuff—no Java runtime, WebSphere Application Server, Tomcat or PHP server required.

Example 1: The Simple Case

For the first example, I have a very simple UI consisting of a button and a text area. This EGL-constructed, browser-based UI looks like Figure 1.

Clicking the “Call Program” button fires off a program call via XMLService. The RPG program I call accepts a character parameter and returns that same parameter with “Hello” on the front of it. The idea is that I can pass in any name and get back “Hello <name>”. The complete RPG source is:

D MyRPG           PR                  ExtPgm('MYRPG')      
D  parm                         40                         

D MyRPG           PI                                       
D  parm                         40                         

/free                                                     
 parm = 'Hello ' + parm;                                  
                                                          
 *inlr = *on;                                             
/end-free                                                 

When I click the button on the UI, the RPG program is called and I see the results in the text area. A successful call looks like Figure 2.

The EGL code involved passes a formatted XML document to XMLService. The complete code for the EGL solution appears in Code Sample 1. (An EDT project containing these examples is available for download on my website at www.dandarnellonline.com.) The service interface named XMLServiceSimple defines a function provided by the service (as well as any parameters going into and coming back from the function). The record named XMLServiceFormData is a data structure that defines the form data the service requires. The handler named TextXMLServiceCallSimple defines a browser-based rich-client interface. The handler provides the UI definition and invokes the service via the service interface definition. My name is passed as a parameter in a hardcoded fashion in a formatted XML string:

xmlin= "<?xml version=\"1.0\" encoding=\"UTF-
8\"?><pgm lib=\"DDARNELL\" name=\"MYRPG\"><parm
by=\"ref\" io=\"both\"><data
type=\"40a\">Dan</data></parm></pgm>",

(Working with manually formatted XML documents is time consuming and error-prone but I take care of this in the example that follows.)

Note that you don’t see the actual address of the service (e.g., http://www.mytestserver.com/cgi-bin/xmlcgi.pgm) anywhere in the source code. Establishing the address of a service is a deployment descriptor setting in an EDT project. Separating the service address from the application logic in this way lets me deploy to different environments (e.g., test, production) without changing source code. The deployment descriptor for my examples appears in Figure 3.

Example 2: Adding Extensibility

The simple case works fine but formatting your own XML to pass as a parameter to XMLService is not “real world” or at least not very robust. For the next foray into the world of XMLService, I use the EDT tools to create a more programmer-friendly interface to the service.

The EDT tooling provides a wizard for creating structures that represent XML schema (based on an XML schema definition or using a formatted XML document). I fed the wizard my formatted XML string from the first example program and the wizard created something like:

record XMLServiceParms {@XMLRootElement{name = "pgm"}}
           lib string {@XMLAttribute{}};
           name string {@XMLAttribute{}};
           parms Parm[] {@XMLElement{name = "parm"}}; 
end
record Parm 
           passBy string {@XMLAttribute{name = "by"}};
           io string {@XMLAttribute{}};
           data Data; 
end
record Data {@XMLValue {kind = XMLStructureKind.simpleContent}}
           dataType string {@XMLAttribute{name = "type"}};
           value string;
end

I’m keeping to a basic program call here and intentionally not generating a structure that includes all of the bells and whistles supported by XMLService. Program, parameter and data descriptions can get complex but the idea is to give you a digestible example you can expand upon. Also, I renamed a few elements in the generated structure to make for more readable application code.

The net result is that by spending a few seconds with a wizard I now have an extensible structure for making XMLService calls and I don’t have to fiddle with any manual XML document formatting or do any hardcoding.

I changed the UI so that it’s more flexible too. I enter my name in the first input box and click the button to get the results like Figure 4.

The EGL code involved is falling-off-a-log simple. First, my interface definition changes slightly to indicate that the response I expect to receive is formatted XML data:

interface XMLService

function callProgram(xmlServiceFormData XMLServiceFormData in)
returns(XMLServiceParms)
     {@PostRest{ requestFormat = _FORM, responseFormat = XML}};
end

The input parameter expected by the callProgram function hasn’t changed—it’s still a structure representing data to be passed as form data.

The UI code looks quite a bit different. I chose to use a layout manager to make composition of the graphical elements easier to manage. I didn’t write all that layout code though. With the visual editor in the EGL tooling, I’m able to drag-and-drop UI elements to create my application and the layout “glue” is managed for me. My new handler appears in Code Sample 2.

Note that prior to invoking the callProgram function, I’m now able to easily establish the program I want to call and the parameters I want to pass. The definition of the program to call looks like:

           myPGMParms XMLServiceParms {lib = "DDARNELL", name = "MYRPG"};

Individual parameters that I want to pass to my RPG program are added to an array, like:

           myPGMParms.parms = new Parm[0];
           myPGMParms.parms.appendElement(new Parm { 
                       passBy="ref", io="both",
data = new Data { 
dataType = "40a", value = nameField.text } } );

The value of the parameter comes from the input field on the UI. There’s no more hardcoded or hand-coded XML of any kind, only a function call that parses the structured program and parameter data into the XML document required by the service:

           xmlin = XMLlib.convertToXML(myPGMParms, true),

When the service call returns, I’m able to access individual return parameters via an array. For the return data, I don’t even have to call a function to parse the XML—that was done for me based on my interface definition. Here I’m setting the result field on my UI to the value of the first parameter in the document returned by the service:

           resultField.text = result.parms[1].data.value;

It shouldn’t take much to flesh out the XML record definitions such that all of the XMLService options are represented. With that done, you can have a toolkit for using EGL to leverage all of the amazing functionality that XMLService provides.

Dan Darnell is an IBM consultant and author.


comments powered by Disqus
Buyers Guide

Advertisement

New and Improved XML-INTO

Namespace support makes the opcode a viable option

Authenticating on the Web

The finer points of OpenRPGUI, Part 1

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
IBMi News Sign Up Today! Past News Letters

Advertisement