TechTip: Get Real-Time Integration Between Your PC Application and Your System i

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Connect to multiple databases with a simple variable that detects database type and enables code to apply to a program or stored procedure written on multiple platforms.

 

Sometimes you need real-time integration between a PC server and a System i. It might be something simple, like accessing a file and getting a value back. Of course, that's not rocket science: an ODBC connection and a few lines of code on the PC application solve that. But what if you need more complex information? Something along the lines of a business rule validation that already exists on an RPG program or a comprehensive data set—for example, a client's debt report divided by debt age (30, 60, and 90 days) or a query to find out if a certain item exists in stock and how long retrieving it would take.

 

As always, there are several possibilities to tackle this. You can replicate the business logic on your PC application, create a complex view on your i database, or simply reuse existing programs and invoke them from your PC application. All you need is an ODBC connection and a few tricks.

 

Consider the previously mentioned client's debt report, but with a tweak: the PC application also needs to know if the client can increase its debt. In this example, that is not a simple check and the business rules are already implemented in an RPG program. We'd have to reproduce the business rules on the PC application, with all the data requirements associated with it, which is not a cost-effective solution. One workaround is to invoke an RPG program that retrieves the debt aging and also the approval or rejection for additional debt. So what are the parameters? As input, we'd need the system (test or production), the client ID, and a reference date (to calculate the aging). As output, we'd have the total debt, the debt aging, a flag with the "additional debt allowed Y/N," and a return code.

 

Input

Parameter

Description

Client ID

Client ID (shared key between the PC application and the main database)

 

 

Output

Parameter

Description

Total Debt

Client's total debt

Debt 30 Days

Invoices outstanding up to 30 days

Debt 60 Days

Invoices outstanding up to 60 days

Debt 90 Days

Invoices outstanding 90 days or more

Additional Debt Allowed

Yes/No flag indicating if additional debt is allowed for this client

Return Code

Flag to indicate if the call was successful

 

Note that the system type is purely optional. I'm mentioning it because most shops have a dedicated test system or at least a separate test library list (I'll discuss this further later).

 

This example uses VB and an ADO DB connection, but you can easily use other programming languages to do the same. An IBM Redbook covers this subject in depth.

 

Now, let's go over the code, step by step, starting with the declarations section:

 

Dim sCall As String

    'Connect to System i

    Set oCmd = New ADODB.Command

 

It starts by declaring a string variable, sCall, that will contain the program's name and full path, as well as its parameters. Then, it creates a new ADO command, which will be the support structure for the invocation.

 

Next, the previously mentioned parameters are added:

 

    'set input params

    Set oParam = oCmd.CreateParameter("inSystem", adChar, adParamInput, 1, mvarInSystem)

    oCmd.Parameters.Append oParam

    Set oParam = oCmd.CreateParameter("inClientID", adChar, adParamInput, 2, mvarClientID)

    oCmd.Parameters.Append oParam

    .....

    Set oParam = oCmd.CreateParameter("outReturnCode", adChar, adParamOutput, 255)

    oCmd.Parameters.Append oParam

    sCall = sNrParams(oCmd.Parameters.Count)

 

Only the first two (system type and client ID) and the last (the return code) are presented. I'm not mentioning all of them because it's basically the same code, over and over.

 

After all the parameters are added, the structure is placed upon its final destination: the sCall string. By now, sCall contains a data structure with our parameters. The next step is to set up the call to the System i program. This call will occur without a library list, so the called System i program needs to set it up. For that, the system type parameter is relevant. If the test and production environments are in separate servers, the connection string will differ. If they're on the same server, they'll use different library lists. So the following is required to take care of that:

 

    ' Compose the program invocation command, taking into account the system type (Production or Test)

    If (mvarInSystem = "P") Then

        sCall = "{{CALL " & URL_LIBRARY_PROD & URL_ProgName & "(" & sCall & ")}}"

    ElseIf (mvarInSystem = "T") Then

        sCall = "{{CALL " & URL_LIBRARY_TEST & URL_ProgName & "(" & sCall & ")}}"

    End If

 

URL_LIBRARY_PROD contains the name of the production library where the called program resides; URL_LIBRARY_TEST is the same for the test library.

 

URL_ProgName contains the name of the program to be called.

 

Now that the call string is complete, let's prepare the command accordingly and get the data:

 

   'Prepare command string

    oCmd.CommandType = adCmdText

    oCmd.CommandText = sCall

   

    'Get data

    subConnAS400 "AS400", oCmd

 

This operation will fill the output parameters with the values returned by the RPG program. If everything goes well, we'll get four amounts, a yes/no flag, and a success return code ('1' means success, '0' means failure). To finalize our little example, we'll check for the return code and proceed accordingly:

 

   mvarOutSuccess = IIf(Trim(oCmd.Parameters("outReturnCode").Value) = "1", True, False)

    If mvarOutSuccess Then

    

      'If the program ended normally, proccess the output parameters   

     

       .....

    End If

 

To wrap it up, here's the complete code for this example:

 

Dim sCall As String

    'Connect to System i

    Set oCmd = New ADODB.Command

    'set input params

    Set oParam = oCmd.CreateParameter("inSystem", adChar, adParamInput, 1, mvarInSystem)

    oCmd.Parameters.Append oParam

    Set oParam = oCmd.CreateParameter("inClientID", adChar, adParamInput, 2, mvarClientID)

    oCmd.Parameters.Append oParam

    .....

    Set oParam = oCmd.CreateParameter("outReturnCode", adChar, adParamOutput, 255)

    oCmd.Parameters.Append oParam

    sCall = sNrParams(oCmd.Parameters.Count)

    ' Compose the program invocation command, taking into account the system type (Production or Test)

    If (mvarInSystem = "P") Then

        sCall = "{{CALL " & URL_LIBRARY_PROD & URL_ProgName & "(" & sCall & ")}}"

    ElseIf (mvarInSystem = "T") Then

        sCall = "{{CALL " & URL_LIBRARY_TEST & URL_ProgName & "(" & sCall & ")}}"

    End If

    'Prepare command string

    oCmd.CommandType = adCmdText

    oCmd.CommandText = sCall

   

    'Get data

    subConnAS400 "AS400", oCmd

    mvarOutSuccess = IIf(Trim(oCmd.Parameters("outReturnCode").Value) = "1", True, False)

    If mvarOutSuccess Then

    

      'If the program ended normally, proccess the output parameters   

     

       .....

    End If

 

A final note about the ODBC connection: I've assumed that this part should be easy, especially if you've read the IBM documentation. But here's a small piece of code that might help:

 

' Make an ADO connection to the database

' ================================================================

Public Function InitEnvironment(ByVal iDBType As DBType, ByVal sAppName As String, ByVal sUserID As String, ByVal sPassw As String, ByVal sServer As String, ByVal sDatabase As String, ByVal CursorLocation As DBCursorLocation) As ADODB.Connection

On Error GoTo errHandler

  

   Dim ConnectStr As String

   Dim oConn As New ADODB.Connection

  

   Set InitEnvironment = Nothing

  

   oConn.CursorLocation = CursorLocation

  

   Select Case iDBType

   'SQL SERVER

   Case dbSQLServer

      oConn.Provider = "SQLOLEDB"

      oConn.Open "Data Source=" & sServer & ";Initial Catalog=" & sDatabase & ";ApplicationFONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-ansi-language: EN-GB" lang=EN-GB>      Set InitEnvironment = oConn

     

   'ORACLE

   Case dbOracle

      oConn.Provider = "MSDAORA.1"

      oConn.CursorLocation = adUseClient

      sServer = sDatabase

      oConn.Open "Data Source=" & sServer & ";ApplicationFONT-FAMILY: 'Courier New'; FONT-SIZE: 10pt; mso-ansi-language: EN-GB" lang=EN-GB>     

      Set InitEnvironment = oConn

      

   'AS/400

   Case dbAS400

      oConn.Provider = "IBMDA400"

      oConn.CursorLocation = adUseClient

      oConn.Open "Data Source=" & sServer & ";User ;Password=" & sPassw & ";"

     

      Set InitEnvironment = oConn

     

   Case Else

      Set oConn = Nothing

     

   End Select

  

   Exit Function

errHandler:

   SetError Err.Number, Err.Description & vbNewLine & "(Data Source: " & sServer & " User: " & sUserID & ")", "(InitEnvironment)"

   Set oConn = Nothing

   Set InitEnvironment = oConn

   Exit Function

   Resume

End Function

 

This function allows connections to multiple databases (System i, Oracle, etc.) using a simple variable, IDBType, that detects the database type. Using this, everything that was written before becomes equally applicable to a program or stored procedure written on any of the platforms mentioned on the code.

 

In my next TechTip, I'll explain the RPG side of this interface.

 

And if you need information about unidirectional interfaces (transfer a file and run a program), check out my previous tips:

 

 Author's Note: I would like to thank José Romão for his assistance in writing this article.

 

 

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$0.00 Raised:
$