www.krengeltech.com

Offer XML to Java Customer Maintenance App

From Wiki

Contents

Introduction

User Guide

The developers at Krengel Tech have been busy looking for new non-traditional ways for you to put RPG-XML Suite (RXS) to work. Considering the sole existence of RXS is to process incoming and outgoing XML, the possibilities for how you can benefit your business are endless!

In this article, you will see how to offer non-verbose XML to a Java Customer Maintenance application running on the desktop. Please note that SOAP was not used because that would have added unnecessary overhead. By eliminating more complex XML we were able to use a very light weight parser/composer on the Java end which can be found here: http://nanoxml.cyberelf.be/. Note that they also have a port for C#.NET if you are looking to accomplish the same thing from the Visual Studio environment.

The basic concept here is that we developed a Java desktop application that draws the UI and based on button clicks makes XML HTTP calls out to the System i5 and receives the response back for displaying to the user. In this case RPG-XML Suite is used to facilitate a handful of validation and file I/O operations, but imagine if you could drive the entire desktop user interface completely from RPG without any need for Java knowledge on your staff to add/change GUI screens!? Stay tuned as we have some more exciting things in store!

Download it now!

Note that you don't have to install the System i5 components if you don't want to. By default the GUI application will connect to Krengel Tech's System i5 over the internet.

File: MYLIB/CUSTMST

      **************************************************************************
      *  File: CUSTMST
      *  Use: Store customer information.
      **************************************************************************
     A                                      UNIQUE
     A          R CUSTMSTR
     A            CUSTNBR        5P 0       COLHDG('Cust Nbr')
     A            FNAM          15A         COLHDG('First Name')
     A            LNAM          15A         COLHDG('Last Name')
     A            CMPNY         20A         COLHDG('Company')
     A            ADR1          20A         COLHDG('Address 1')
     A            ADR2          20A         COLHDG('Address 2')
     A            CTY           15A         COLHDG('City')
     A            STT            2A         COLHDG('State')
     A            ZIPCD          5A         COLHDG('Zip Code')
     A            PHN           18A         COLHDG('Phone')
 
     A          K CUSTNBR

Module: CUSTFN

      //------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2007-06-08
      // @Desc: Modular customer RPG service program.
      // @Compile: ADDLIBLE MYLIB
      //           CRTRPGMOD
      //             MODULE(MYLIB/CUSTFN) SRCFILE(MYLIB/QSOURCE) SRCMBR(CUSTFN)
      //
      //           CRTSRVPGM
      //             SRVPGM(MYLIB/CUSTSV)
      //             MODULE(MYLIB/CUSTFN) SRCFILE(MYLIB/QSOURCE)
      //------------------------------------------------------------------------
     h nomain
 
     fCUSTMST   uf a e           k disk    prefix('CM.')
     d CM            e ds                  qualified extname(CUSTMST)
 
      /copy qsource,CustCP
 
 
      //------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2007-06-08
      // @Desc: Get the next available customer number.
      //------------------------------------------------------------------------
     p Cust_nextNbr    b                   export
     d Cust_nextNbr    pi
     d  pError                             like(Cust_Error)
     d  pNbr                               like(CM.CUSTNBR)
      /free
 
         clear pError;
         setgt *hival CUSTMST;
         readp CUSTMST;
         pNbr = CM.CUSTNBR + 1;
         clear CUSTMSTR;
         CM.CUSTNBR = pNbr;
         write CUSTMSTR;
 
      /end-free
     p                 e
 
 
      //------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2007-06-08
      // @Desc: Retrieve a customer record.
      //------------------------------------------------------------------------
     p Cust_getRec     b                   export
     d Cust_getRec     pi
     d  pError                             like(Cust_Error)
     d  pCustRec                           likeds(CM)
     d  pCustNbr                           like(CM.CUSTNBR)
      /free
 
         clear pError;
         clear pCustRec;
         chain(n) pCustNbr CUSTMST;
         if not %found;
           pError = 'Customer Not Found';
         else;
           pCustRec = CM;
         endif;
 
      /end-free
     p                 e
 
 
      //------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2007-06-08
      // @Desc: Save a customer record
      //------------------------------------------------------------------------
     p Cust_save       b                   export
     d Cust_save       pi
     d  pError                             like(Cust_Error)
     d  pCustRec                           likeds(CM)
      /free
 
       monitor;
         clear pError;
         if ( pCustRec.CustNbr = 0
           or pCustRec.FNam = *blanks
           or pCustRec.LNam = *blanks
           or pCustRec.Cmpny = *blanks
           or pCustRec.Adr1 = *blanks
           or pCustRec.Cty = *blanks
           or pCustRec.Stt = *blanks
           or pCustRec.ZipCd = *zeros
           or pCustRec.Phn = *blanks );
            pError = 'Not all fields were set!';
           return;
         endif;
 
         chain pCustRec.CustNbr CUSTMST;
         CM = pCustRec;
         if %found(CUSTMST);
           update CUSTMSTR;
         else;
           write CUSTMSTR;
         endif;
       on-error;
         pError = 'Error occurred during save of customer!';
       endmon;
 
      /end-free
     p                 e

Copy book: CUSTCP

     D Cust_nextNbr    pr
     D  pError                             like(Cust_Error)
     D  pNbr                               like(CM.CUSTNBR)
 
     D Cust_getRec     pr
     D  pError                             like(Cust_Error)
     D  pCustRec                           likeds(CM)
     D  pCustNbr                           like(CM.CUSTNBR)
 
     D Cust_save       pr
     D  pError                             like(Cust_Error)
     D  pCustRec                           likeds(CM)
 
 
     D Cust_Error      s             50A

Binder Language (used to create *SRVPGM)

  strpgmexp
    export symbol(Cust_nextNbr)
    export symbol(Cust_getRec)
    export symbol(Cust_save)
  endpgmexp

RPG-XML Suite web service program

      //*******************************************************************************************
      // @Author: Aaron Bartell
      // @Created: 2005-08-23
      // @Desc:
      // @Compile: CRTBNDRPG PGM(MYRXS/WSCUST) SRCFILE(MYLIB/QSOURCE) SRCMBR(WSCUST)
      //*******************************************************************************************
     H dftactgrp(*no) bnddir('RXSBND': 'SINBND')
 
      /copy rxs,RXSCp
      /copy qsource,CustCp
 
     D allHandler      pr
     D  pType                              value like(RXS_Type)
     D  pXPath                             value like(RXS_XPath)
     D  pData                              value like(RXS_XmlData)
     D  pDataLen                           value like(RXS_Length)
 
     D errHandler      pr
     D  pCurLine                     10i 0 value
     D  pCurCol                      10i 0 value
     D  pErrStr                    1024a   value varying
 
     D errRsp          pr
 
     D gAction         s             25a   varying
 
     D CM            e ds                  qualified extname(CUSTMST)
     D gError          ds                  likeds(RXS_Error) inz
     D gXml            s          65535a   varying
     D gCustErr        s                   like(Cust_Error)
     D gCustNbr        s                   like(CM.CUSTNBR)
      /free
 
       monitor;
         clear gError;
         clear gAction;
 
         if RXS_libLEExists('MYLIB') <= 0;
           RXS_addLibLE('MYLIB');
         endif;
 
         gXml = RXS_readStdIn();
 
         RXS_allElemContentHandler(%paddr(allHandler));
         RXS_addHandler('/ENV@ACTION': %paddr(allHandler));
         RXS_parse(gXml: RXS_VAR: %paddr(errHandler));
 
         if gError.code <> *blanks;
           RXS_stdOutError('error': gError: *on);
           *inlr = *on;
           return;
         endif;
 
         exsr compose;
 
       on-error;
         RXS_stdOutError('error': RXS_catchError(): *on);
       endmon;
 
       *inlr = *on;
 
 
 
       //--------------------------------------------------------------------------------------------
       // @Author: Aaron Bartell
       // @Created: 2005-08-03
       // @Desc: Using the template engine compose the response and send it to standard out (i.e.
       //        RXS_STDOUT).
       //--------------------------------------------------------------------------------------------
       begsr compose;
 
       // Compose xml
       RXS_initTplEng(RXS_STDOUT: *omit: *omit: *omit: *omit: *off);
       RXS_loadTpl('wscust.tpl': '::': '': '.:': ':.');
       RXS_wrtSection('HTTP_HEAD');
 
       RXS_wrtSection('env_beg');
       select;
       when gAction = 'CUST_NEXTNBR';
         Cust_nextNbr(gCustErr: gCustNbr);
         if gCustErr <> *blanks;
           RXS_updVar('ERROR': gCustErr);
           RXS_wrtSection('ERROR');
         else;
           RXS_updVar('CUSTNBR': %char(gCustNbr));
           RXS_wrtSection('CUSTNBR');
         endif;
       when gAction = 'CUST_SAVE';
         Cust_save(gCustErr: CM);
         if gCustErr <> *blanks;
           RXS_updVar('ERROR': gCustErr);
           RXS_wrtSection('ERROR');
         endif;
       when gAction = 'CUST_GETREC';
         Cust_getRec(gCustErr: CM: gCustNbr);
         if gCustErr <> *blanks;
           RXS_updVar('ERROR': gCustErr);
           RXS_wrtSection('ERROR');
         else;
           RXS_updVar('CUSTNBR': %char(CM.CUSTNBR));
           RXS_updVar('FNAM': CM.FNAM);
           RXS_updVar('LNAM': CM.LNAM);
           RXS_updVar('CMPNY': CM.CMPNY);
           RXS_updVar('ADR1': CM.ADR1);
           RXS_updVar('ADR2': CM.ADR2);
           RXS_updVar('CTY': CM.CTY);
           RXS_updVar('STT': CM.STT);
           RXS_updVar('ZIPCD': CM.ZIPCD);
           RXS_updVar('PHN': CM.PHN);
           RXS_wrtSection('CUSTMST');
         endif;
       other;
         RXS_updVar('ERROR': 'No action specified');
       endsl;
 
       RXS_wrtSection('env_end': *on);
 
       endsr;
 
      /end-free
      //--------------------------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2005-08-03
      // @Desc: This local sub procedure will be called for each element content and attribute event
      //        that occurs during the parsing of the env document. Based on the event this sub
      //        procedure is being notified of it will place the value in the appropriate global
      //        variable.
      //--------------------------------------------------------------------------------------------
     P allHandler      b
     D allHandler      pi
     D  pType                              value like(RXS_Type)
     D  pXPath                             value like(RXS_XPath)
     D  pData                              value like(RXS_XmlData)
     D  pDataLen                           value like(RXS_Length)
      /free
 
       select;
 
       when pXPath = '/ENV@ACTION';
         gAction = pData;
 
       when pXPath = '/ENV/CUSTMST/CUSTNBR/';
         CM.CUSTNBR = RXS_charToNbr(pData: 0);
       when pXPath = '/ENV/CUSTMST/FNAM/';
         CM.FNAM = pData;
       when pXPath = '/ENV/CUSTMST/LNAM/';
         CM.LNAM = pData;
       when pXPath = '/ENV/CUSTMST/CMPNY/';
         CM.CMPNY = pData;
       when pXPath = '/ENV/CUSTMST/ADR1/';
         CM.ADR1 = pData;
       when pXPath = '/ENV/CUSTMST/ADR2/';
         CM.ADR2 = pData;
       when pXPath = '/ENV/CUSTMST/CTY/';
         CM.CTY = pData;
       when pXPath = '/ENV/CUSTMST/STT/';
         CM.STT = pData;
       when pXPath = '/ENV/CUSTMST/ZIPCD/';
         CM.ZIPCD = pData;
       when pXPath = '/ENV/CUSTMST/PHN/';
         CM.PHN = pData;
       when pXPath = '/ENV/CUSTNBR/';
         gCustNbr = RXS_charToNbr(pData: 0);
 
       endsl;
 
      /end-free
     P                 e
 
 
      //--------------------------------------------------------------------------------------------
      // @Author: Aaron Bartell
      // @Created: 2005-08-03
      // @Desc: If an error occurs this local sub procedure will be called by the parser.
      //--------------------------------------------------------------------------------------------
     P errHandler      B
     D errHandler      PI
     D  pCurLine                     10i 0 value
     D  pCurCol                      10i 0 value
     D  pErrStr                    1024a   value varying
      /free
 
       gError.code = 'RXS3.1';
       gError.severity = 100;
       gError.pgm = 'RXS3.errHandler';
       gError.text =
         'Line:' + %char(pCurLine) +
         ' Column:' + %char(pCurCol) +
         ' ' + pErrStr;
 
      /end-free
     P                 E

RPG-XML Suite template file

/www/myrxs/templates/wscust.tpl

::HTTP_HEAD 
Content-type: text/xml 
 
::env_beg 
<env>
 
::CUSTMST 
<CUSTMST>
  <CUSTNBR>.:CUSTNBR:.</CUSTNBR>
  <FNAM>.:FNAM:.</FNAM>
  <LNAM>.:LNAM:.</LNAM>
  <CMPNY>.:CMPNY:.</CMPNY>
  <ADR1>.:ADR1:.</ADR1>
  <ADR2>.:ADR2:.</ADR2>
  <CTY>.:CTY:.</CTY>
  <STT>.:STT:.</STT>
  <ZIPCD>.:ZIPCD:.</ZIPCD>
  <PHN>.:PHN:.</PHN>
</CUSTMST>
 
::CUSTNBR 
<CUSTNBR>.:CUSTNBR:.</CUSTNBR>
 
::ERROR 
<ERROR>.:ERROR:.</ERROR>
 
::env_end 
</env>