If you have worked on IBM i application development, you must have heard about RPG programming language. Developers use it on a IBM system โ the AS400 or iSeries. But what is RPG? What is it used for? Should you start learning it? In this article, you will find all the details.
What does RPG stand for?
RPG stands for Report Programming Generator. It refers to a high-level programming language that includes a series of procedural steps to complete. RPG was developed by IBM in the year 1959. It still works as the primary programming language for IBM computers.
The meaning of RPG has gone through several changes since its inception throughout these years. Early versions of RPG ran on the old AS400 and iSeries machines as the primary programming language. The latest version is known as RPG IV. It is used for commercial business application development on IBM’s minicomputer system.
Who uses the RPG language?
Software developers and programmers use RPG. It enables you to create, update, and maintain business applications on IBM computer systems. Developers use it for a variety of purposes. For example, users can utilize RPG to automate business workflow.
Why should developers learn RPG?
There are plenty of reasons for learning RPG programming, including widespread use and in-demand skill. Letโs find them out.
Are businesses still using RPG programming language?
IBM i is still considered one of the leading enterprise platforms. Small and large business users rely on it to power critical operations. The majority of these companies are still using multiple RPG-based applications. The apps need maintenance, updates, and modernization. Hence, developers should learn RPG programming, as businesses are still using it to power their operations.
Does the market lack RPG developers with high skills?
Thousands of businesses are using RPG programming language for their apps. However, there is a shortage of skilled developers. From 2017 to 2020, around 33% of active RPG and COBOL developers went to retirement. Also, the new generation of programmers are not interested in โlegacyโ languages like RPG. Developers are more interested in investing time and effort in modern programming languages. Hence, the talent pool is continuously shrinking. Developers can turn this situation into a great opportunity. By learning RPG, you can enter into a space that has high demand but less competition. As a result, you have a higher chance of landing highly paid jobs.
Can integrating the programs with modern technologies be time-consuming?
If you want to use RPG programs, you have to integrate them with the latest tools and technologies. Otherwise, it will be impossible to meet the business demands. However, integrating the RPG programs with modern technologies and tools can be very difficult for developers. It can take a lot of time.
To solve this common issue, you can use modern low-code tools. They enable you to modernize RPG business apps without migration. As a result, they have become massively popular. For example, developers can utilize Visual LANSA to simplify the modernization of legacy tools. It has the ability to make application development workflow up to ten times faster. Hence, you can quickly modernize your legacy app.
Read: Why You Should Modernize Your RPG and COBOL 5250 Apps
What is RPG programming language used for?
Developers use RPG language for commercial business application development on IBMโs leading minicomputer system โ the AS400 or iSeries. It provides users with an interactive programming environment. Hence, you can conveniently enhance existing software applications or automate the existing business processes.
How can I connect my RPG programs with modern web and mobile applications with LANSA?
Developers can connect RPG programs with apps by using LANSA integrator. It is based on the Java Service Framework. It enables easy integration between Java programs and RPG applications.
LANSA integrator supports a wide range of B2B technologies such as FTP, FTPS, SFTP, HTTP, HTTPS, SMTP, POP3, SOAP, and JMS. They eliminate complexities and simplify the integration process. Hence, you can save time and focus more on the business requirements.
Letโs take a look at one of the practical examples of using LANSA integrator.
ExcelService Example
Let’s take a look at some source code of an ExcelService example built in RPG and after that we will take a look at the same example built in LANSA’s RDMLX. The RDMLX version is much shorter than the RPG version.
What does the example look like in RPG?
Refer to shipped RPG source file QRPGLRSRC and CRTDEMO program source in QCLSRC source file.
This example is self contained and requires no additional work besides compilation.
H OPTION(*SRCSTMT : *NODEBUGIO) DFTACTGRP(*NO) ACTGRP(*CALLER)
H BNDDIR('JSMBNDDIR')
*
* V6R1 - Limits
* Maximum data structure size is 16,773,104 bytes
* Data structure size = element size * occurrence
*
D ListDef1 S 60A DIM(3) CTDATA
D ListDefSize S 10I 0 INZ(0)
D ListEntSize S 10I 0 INZ(0)
D ListCount S 10I 0 INZ(0)
D ListMaxCount S 10I 0 INZ(0)
*
D JSMHDL S 4A INZ(*BLANKS)
D JSMSRV S 50A INZ(*BLANKS)
D JSMSTS S 20A INZ(*BLANKS)
D JSMMSG S 512A INZ(*BLANKS)
D JSMCMD S 512A INZ(*BLANKS)
D ZEROLENGTH S 10I 0 INZ(0)
*
D COUNT S 6S 0 INZ(0)
*
D LST1 DS OCCURS(9999)
D PRDID 10A
D PRDNME 20A
D PRDAMT 10P 2
*
D LST2 DS DIM(9999) QUALIFIED
D PRDID 10A
D PRDNME 20A
D PRDAMT 10P 2
*
* JSMX_BEGIN
*
C CALLB(D) 'JSMX_BEGIN'
C PARM *OMIT
C PARM ZEROLENGTH
*
* JSMX_OPEN - USE JSMCLTDTA FOR SERVER
*
C CLEAR JSMSRV
C EVAL JSMSRV = ''
C CALLB(D) 'JSMX_OPEN'
C PARM JSMHDL
C PARM JSMSRV
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* SERVICE_LOAD
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'SERVICE_LOAD' +
C ' SERVICE(ExcelService)' +
C ' TRACE(*YES)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* CREATE
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'CREATE'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* ADD OBJECT(*SHEET)
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'ADD OBJECT(*SHEET)' +
C ' SHEET(MyTest)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* ADD OBJECT(*CELLSTYLE)
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'ADD OBJECT(*CELLSTYLE)' +
C ' TYPE(*NUMBER)' +
C ' COLUMN(5) RANGE(10,20)' +
C ' FONT(*TAHOMA)' +
C ' FORMAT(*FORMAT4)' +
C ' HALIGN(*RIGHT)' +
C ' BACKGROUND(*YELLOW)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* WRITE LIST
*
C EVAL COUNT = 0
C 1 DO 20
C ADD 1 COUNT
C COUNT OCCUR LST1
C EVAL PRDID = 'ID' + %CHAR(COUNT)
C EVAL PRDNME = 'Product ' + %CHAR(COUNT)
C EVAL PRDAMT = 1000.45 + COUNT
C ENDDO
*
* Reset list to beginning
C 1 OCCUR LST1
C EVAL ListDefSize = %SIZE(ListDef1:*ALL)
C EVAL ListEntSize = %SIZE(LST1)
C EVAL ListCount = COUNT
C EVAL ListMaxCount = %ELEM(LST1)
C CALLB(D) 'JSMX_BINDLST'
C PARM JSMHDL
C PARM ListDef1
C PARM ListDefSize
C PARM LST1
C PARM ListEntSize
C PARM ListCount
C PARM ListMaxCount
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* WRITE R1C1
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'WRITE R1C1(10,3)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* WRITE LIST 2
*
C EVAL COUNT = 0
C 1 DO 20
C ADD 1 COUNT
C EVAL LST2(COUNT).PRDID = 'ID' + %CHAR(COUNT)
C EVAL LST2(COUNT).PRDNME = 'NME' + %CHAR(COUNT)
C EVAL LST2(COUNT).PRDAMT = 2000.47 + COUNT
C ENDDO
*
C EVAL ListDefSize = %SIZE(ListDef1:*ALL)
C EVAL ListEntSize = %SIZE(LST2)
C EVAL ListCount = COUNT
C EVAL ListMaxCount = %ELEM(LST2)
C CALLB(D) 'JSMX_BINDLST'
C PARM JSMHDL
C PARM ListDef1
C PARM ListDefSize
C PARM LST2
C PARM ListEntSize
C PARM ListCount
C PARM ListMaxCount
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* WRITE R1C1
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'WRITE R1C1(10,10)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* READ LIST 2
*
C CLEAR LST1
C CLEAR LST2
*
C EVAL ListDefSize = %SIZE(ListDef1:*ALL)
C EVAL ListEntSize = %SIZE(LST2)
C EVAL ListCount = 0
C EVAL ListMaxCount = %ELEM(LST2)
C CALLB(D) 'JSMX_BINDLST'
C PARM JSMHDL
C PARM ListDef1
C PARM ListDefSize
C PARM LST2
C PARM ListEntSize
C PARM ListCount
C PARM ListMaxCount
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* READ R1C1
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'READ R1C1(10,15) ROWCOUNT(5)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* DSPLY ListCount
* DO LISTCOUNT COUNT
* EVAL PRDID = LST2(COUNT).PRDID
* EVAL PRDNME = LST2(COUNT).PRDNME
* EVAL PRDNME = %CHAR(LST2(COUNT).PRDAMT)
* DSPLY LST2(COUNT)
* DSPLY PRDNME
* ENDDO
*
* SAVE FILE
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'SAVE' +
C ' FILE(demo.xlsx)'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* CLOSE
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'CLOSE'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* SERVICE_UNLOAD
*
C CLEAR JSMCMD
C EVAL JSMCMD = 'SERVICE_UNLOAD'
C CALLB(D) 'JSMX_COMMAND'
C PARM JSMHDL
C PARM JSMCMD
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* JSMX_CLOSE
*
C CALLB(D) 'JSMX_CLOSE'
C PARM JSMHDL
C PARM JSMSTS
C PARM JSMMSG
C CALLP checkSTS(JSMSTS:JSMMSG)
*
* JSMX_END
*
C CALLB(D) 'JSMX_END'
*
C SETON LR
********************************
* Procedure to check JSM status
********************************
P checkSTS B
D checkSTS PI N
D csJSMSTS CONST LIKE(JSMSTS)
D csJSMMSG CONST LIKE(JSMMSG)
D csMSGTXT S 512A
C IF csJSMSTS <> 'OK'
C EVAL csMSGTXT = %TRIM(csJSMSTS) + ' ' +
C %TRIM(csJSMMSG)
C CALLP sendMSG(csMSGTXT)
C RETURN *OFF
C ENDIF
C RETURN *ON
P E
**************************************
* Procedure to send a program message
**************************************
P sendMSG B
D sendMSG PI
D smMSGTXT 512A VALUE
D smMSGT S 10A INZ('*DIAG')
D smMSGI S 7A INZ('CPF9897')
D smMSGF S 20A INZ('QCPFMSG *LIBL ')
D smMSGL S 10I 0 INZ(%SIZE(smMSGTXT))
D smSTKE S 10A INZ('*')
D smSTKC S 10I 0 INZ(1)
D smMSGK S 4A INZ(*BLANK)
D smERRC S 10I 0 INZ(0)
C CALL 'QMHSNDPM'
C PARM smMSGI
C PARM smMSGF
C PARM smMSGTXT
C PARM smMSGL
C PARM smMSGT
C PARM smSTKE
C PARM smSTKC
C PARM smMSGK
C PARM smERRC
P E
**CTDATA ListDef1
PRDID A000001000
PRDNME A000002000
PRDAMT P000001002
What does this example look like in LANSA’s RDMLX?
This example is self contained and requires no additional work besides compilation.
Function Options(*DIRECT)
*
Define Field(#PRDID) Type(*CHAR) Length(10)
Define Field(#PRDNME) Type(*CHAR) Length(20)
Define Field(#PRDAMT) Type(*DEC) Length(10) Decimals(2)
Define Field(#COUNT) Type(*DEC) Length(5) Decimals(0)
*
Def_List Name(#LST1) Fields(#PRDID #PRDNME #PRDAMT) Type(*WORKING)
*
* JSMX_BEGIN
*
Use Builtin(JSMX_BEGIN)
*
* JSMX_OPEN
*
Use Builtin(JSMX_OPEN) With_Args('LOCALHOST:7560') To_Get(#JSMXSTS #JSMXMSG #JSMXHDLE1)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* SERVICE_LOAD
*
#JSMXCMD := 'SERVICE_LOAD SERVICE(ExcelService) TRACE(*YES)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* CREATE
*
#JSMXCMD := 'CREATE'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* ADD OBJECT(*SHEET)
*
#JSMXCMD := 'ADD OBJECT(*SHEET) SHEET(MyTest)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* ADD OBJECT(*CELLSTYLE)
*
#JSMXCMD := 'ADD OBJECT(*CELLSTYLE) TYPE(*NUMBER) COLUMN(5) RANGE(10,20) FONT(*TAHOME) FORMAT(*FORMAT4) HALIGN(*RIGHT) BACKGROUND(*YELLOW)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* WRITE LIST
*
Begin_Loop Using(#COUNT) To(20)
#PRDID := 'ID' + #COUNT.AsString
#PRDNME := 'Product' + #COUNT.AsString
#PRDAMT := 2000.45 + #COUNT
Add_Entry To_List(#LST1)
End_Loop
*
#JSMXCMD := 'WRITE R1C1(10,3)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG #LST1)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* READ LIST
*
Clr_List Named(#LST1)
*
#JSMXCMD := 'READ R1C1(10,3) ROWCOUNT(5)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG #LST1)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
Selectlist Named(#LST1)
* Display Fields(#PRDID #PRDNME #PRDAMT)
Endselect
*
* SAVE FILE
*
#JSMXCMD := 'SAVE FILE(demo.xlsx)'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* CLOSE
*
#JSMXCMD := 'CLOSE'
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 #JSMXCMD) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* SERVICE_UNLOAD
*
Use Builtin(JSMX_COMMAND) With_Args(#JSMXHDLE1 'SERVICE_UNLOAD') To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* JSMX_CLOSE
*
Use Builtin(JSMX_CLOSE) With_Args(#JSMXHDLE1) To_Get(#JSMXSTS #JSMXMSG)
Execute Subroutine(CHECK) With_Parms(#JSMXSTS #JSMXMSG)
*
* JSMX_END
*
Use Builtin(JSMX_END)
*
* SUB ROUTINES
*
Subroutine Name(CHECK) Parms((#JSMXSTS *RECEIVED) (#JSMXMSG *RECEIVED))
*
If Cond('#JSMXSTS *NE OK')
*
Use Builtin(JSMX_CLOSE) With_Args(#JSMXHDLE1) To_Get(#JSMXSTS #JSMXMSG)
*
Menu Msgtxt('Java service error has occurred')
*
Endif
*
Endroutine
You can find these two and other examples built in RPG and RDMLX in the LANSA documentation.
Can Visual LANSA solve issues with app development in RPG programming language?
Visual LANSA is a low-code development platform available for free. It is feature-rich. It enables you to simplify the development process. You can use Visual Lansa to quickly modernize legacy apps. It gives you access to a low-code method. Hence, you can easily build apps and deploy them to IBM i.
Also, you donโt have to learn RPG programming language to use it. You donโt even need to learn other languages, like Java. You can do everything from defining to deploying app logic with LANSA low-code tools. Also, it has a strong community support. Overall, it offers a great solution for effectively developing and modernizing apps. Therefore, you should definitely consider using Visual LANSA.