fhg
Volume 7, Number 34 -- October 3, 2007

APIs Sometimes Fail (But Programmers Don't Have To)

Published: October 3, 2007

by Ted Holt

My ambition is to eventually be as smart as my teenagers. Some days I think I'll make it. After all, my old man became downright brilliant once I left home and had to start paying my own bills. On other days, like days when I try to write computer programs, I have the gravest of doubts.

One of those days occurred recently, when I spent half a day trying to find a bug in my code. It turned out that a call to the Send Program Message API, QMHSNDPM, was failing, and I wasn't bothering to check whether the call succeeded or not. My friend Cletus the Codeslinger reveled in ragging me about it. "What moron told you you were fit to be a programmer?" he sneered. "If you'd read my assertions article, that wouldn't have happened." Of course, I did read the article--I'm the editor. But it's foolish to argue with someone when he's right.

Most System i APIs, including QMHSNDPM, use a data structure to report errors. (Exceptions are the ILE CEE APIs, which use feedback codes and conditions, and the Unix-type, and National Language Data Conversion, which use the errno variable.) The data structure has two formats--ERRC0100 and ERRC0200. You can use either one. Or you can tell the API to send an escape message, rather than load a data structure.

Let's look at an RPG prototype for the API that got me in trouble.

D SendPgmMsg      pr                  extpgm('QMHSNDPM')
D   MsgID                        7    const
D   MsgFile                     20    const
D   MsgDta                      80    const
D   MsgDtaLen                   10i 0 const
D   MsgType                     10    const
D   MsgQ                        10    const
D   MsgQNbr                     10i 0 const
D   MsgKey                       4
D   Error                      ????

The ninth parameter, which I have defined with question marks for now, tells QMHSNDPM how the programmer wants the API to report errors. The first four bytes of the error parameter contain a binary number, which is the key to the whole thing. If that number is zero, the API is to report errors by sending diagnostic and escape messages. If that number is positive, the API is to report errors through a data structure formatted according to the ERRC0100 format. If that number is negative one, the API is to report errors through the data structure according to the ERRC0200 format.

If you want to receive diagnostic and escape messages, you don't even need a data structure. A scalar value will do. Notice the last line of the prototype, where the error parameter is defined as a four-byte integer.

D SendPgmMsg      pr                  extpgm('QMHSNDPM')
D   MsgID                        7    const
D   MsgFile                     20    const
D   MsgDta                      80    const
D   MsgDtaLen                   10i 0 const
D   MsgType                     10    const
D   MsgQ                        10    const
D   MsgQNbr                     10i 0 const
D   MsgKey                       4
D   Error                       10i 0 const

Here's a call to the API that illustrates this option.

 /free
     monitor;
        SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':
            MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:
            MsgKey: *zero);
        on-error;
            // it bombed; do something
        endmon;

If you prefer to use the data structure, that's fine. I have found ERRC0100 to be sufficient. You can pass it as many bytes as you wish. I recommend a minimum of 16 bytes, but I have come to prefer 272, as this length allows for 256 bytes of message data.

Here's the revised prototype and the data structure for the error feedback.

     D SendPgmMsg      pr                  extpgm('QMHSNDPM')
     D   MsgID                        7    const
     D   MsgFile                     20    const
     D   MsgDta                      80    const
     D   MsgDtaLen                   10i 0 const
     D   MsgType                     10    const
     D   MsgQ                        10    const
     D   MsgQNbr                     10i 0 const
     D   MsgKey                       4
     D   Error                             like(ErrorDS)

     D ErrorDS         ds           272    qualified
     D   BytesProv                   10i 0 inz(%size(ErrorDS))
     D   BytesAvail                  10i 0
     D   ExceptionID                  7
     D                                1
     D   ExceptionDta               256

Here's the call.

SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':
   MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:
   MsgKey: ErrorDS);
if ErrorDS.BytesAvail > *zero;
   // it bombed; do something
endif;

If the call succeeds, you will find a zero in the bytes-available subfield. If the call fails, you will receive a positive value in the bytes-available subfield, a seven-byte message ID in ErrorDS.ExceptionID, and the message data for the error in ErrorDS.ExceptionDta. Do not test the call by checking those last two subfields for non-blanks. After a successful call, they may continue to contain data from an earlier, failed call.

You must use ERRC0200 if you want convertible character support. I've never used ERRC0200, so I threw together an example. You may come up with something better.

Here's the prototype again, with the revised error data structure and a separate scalar variable for exception data.

D SendPgmMsg      pr                  extpgm('QMHSNDPM')
D   MsgID                        7    const
D   MsgFile                     20    const
D   MsgDta                      80    const
D   MsgDtaLen                   10i 0 const
D   MsgType                     10    const
D   MsgQ                        10    const
D   MsgQNbr                     10i 0 const
D   MsgKey                       4
D   Error                             like(ErrorDS)

D ErrorDS         ds          1024    qualified
D   Key                         10i 0 inz(-1)
D   BytesProv                   10i 0 inz(%size(ErrorDS))
D   BytesAvail                  10i 0
D   ExceptionID                  7
D                                1
D   CCSID                       10i 0
D   ExcDtaOffset                10i 0
D   ExcDtaLength                10i 0

D ExceptionDta    s            256

The stand-alone exception data variable is necessary because the location of exception data is not fixed within the data structure. You have to look at the offset and length subfields in order to find the exception data. The following code loads the exception data if the call fails.

clear ExceptionDta;
SendPgmMsg ('CPF9898': 'QCPFMSG   QSYS':             
    MsgDta: %len(MsgDta): '*INFO': '*PGMBDY': 1:     
    MsgKey: ErrorDS);                                
if ErrorDS.BytesAvail > *zero;                      
   // it bombed                                     
   // retrieve the exception data                   
   if ErrorDS.ExcDtaLength <= %size(ExceptionDta);  
      ExceptionDta = %subst(ErrorDS:                
                         ErrorDS.ExcDtaOffset + 1:  
                         ErrorDS.ExcDtaLength);     
   else;                                            
      ExceptionDta = %subst(ErrorDS:                
                         ErrorDS.ExcDtaOffset + 1:  
                         %size(ExceptionDta));      
   // do whatever else                              
   endif;                                           
endif;

I learned a lesson from my experience: Checking for API execution errors is easy. The hard part might be remembering to do so.




                     Post this story to del.icio.us
               Post this story to Digg
    Post this story to Slashdot


Sponsored By
VISION SOLUTIONS

Want to accelerate your business?

Learn how high availability can help you
increase revenue, boost productivity and
win more customers.

Get the must-read whitepaper
"Introduction to System i High Availability."

A free resource from Vision Solutions,
the HA experts.

www.visionsolutions.com


Senior Technical Editor: Ted Holt
Technical Editors: Howard Arner, Joe Hertvik, Shannon O'Donnell, Kevin Vandever
Contributing Technical Editors: Joel Cochran, Wayne O. Evans, Raymond Everhart,
Bruce Guetzkow, Brian Kelly, Marc Logemann, David Morris
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

Sponsored Links

COMMON:  Join us at the annual 2008 conference, March 30 - April 3, in Nashville, Tennessee
Help/Systems:  Discover Robot/SECURITY, the i5/OS security monitoring and auditing software
NowWhatJobs.net:  NowWhatJobs.net is the resource for job transitions after age 40


 

IT Jungle Store Top Book Picks

The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
The System i Pocket RPG & RPG IV Guide: List Price, $69.95
The iSeries Pocket Database Guide: List Price, $59.00
The iSeries Pocket Developers' Guide: List Price, $59.00
The iSeries Pocket SQL Guide: List Price, $59.00
The iSeries Pocket Query Guide: List Price, $49.00
The iSeries Pocket WebFacing Primer: List Price, $39.00
Migrating to WebSphere Express for iSeries: List Price, $49.00
iSeries Express Web Implementer's Guide: List Price, $59.00
Getting Started with WebSphere Development Studio for iSeries: List Price, $79.95
Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
Getting Started with WebSphere Express for iSeries: List Price, $49.00
WebFacing Application Design and Development Guide: List Price, $55.00
Can the AS/400 Survive IBM?: List Price, $49.00
The All-Everything Machine: List Price, $29.95
Chip Wars: List Price, $29.95


 
The Four Hundred
State of the System i: What's Going On in the Market?

Summit Partners Sells Help/Systems to Audax Group

Reader Feedback on EGL: At Least It's Not Java, But It Ain't RPG, Either

IBM Helps Users Migrate to Power6-Based System i Boxes

The Linux Beacon
IDF Server Wrap Up: Intel to Keep the Pressure on AMD

Mandriva Readies Linux 2008 Editions for October

SAP Plants Its Flag in Mid-Market Territory with SaaS Apps

Opsware Adds Storage, Process Management with System 7 Tools

Four Hundred Stuff
Bug Busters Achieves High Availability Milestone with RSF 8.1

LANSA to Deliver Code-Less Business Process Integration for SMBs

Water District Makes Second Run at Electronic Document Retention

The ROI of RF Technology

Big Iron
Hosing z/OS.e and Other Withdrawals

Top Mainframe Stories From Around the Web

Chats, Webinars, Seminars, Shows, and Other Happenings

System i PTF Guide
September 29, 2007: Volume 9, Number 39

September 22, 2007: Volume 9, Number 38

September 15, 2007: Volume 9, Number 37

September 8, 2007: Volume 9, Number 36

September 1, 2007: Volume 9, Number 35

August 25, 2007: Volume 9, Number 34

The Windows Observer
Microsoft Launches Business Intelligence Tool for the Masses

Microsoft Revs Betas of Longhorn, Viridian, Vista SP1

IDF Server Wrap Up: Intel to Keep the Pressure on AMD

Sun Ships Intel-Based Galaxy Rack Servers

The Unix Guardian
Sun Enhances Solaris Developer Edition, Adds Support

Sun Ships Intel-Based Galaxy Rack Servers

IDF Server Wrap Up: Intel to Keep the Pressure on AMD

As I See It: Shocking

Four Hundred Monitor
Four Hundred Monitor's
Full iSeries Events Calendar

THIS ISSUE SPONSORED BY:

WorksRight Software
Vision Solutions
ARCAD Software


Printer Friendly Version


TABLE OF CONTENTS
IFS Commands Give You Generic Access

APIs Sometimes Fail (But Programmers Don't Have To)

Admin Alert: Remotely Accessing an HMC System Console, Part 1

Four Hundred Guru

BACK ISSUES

From the IT Jungle Forums
Crashing processes!

SQL 'Hidden' Field

What's coalesce good for?

How do I transfer output from a query to Excel?

Copying record of join logical file mutiple times





 
Subscription Information:
You can unsubscribe, change your email address, or sign up for any of IT Jungle's free e-newsletters through our Web site at http://www.itjungle.com/sub/subscribe.html.

Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement