17
Wed, Apr
5 New Articles

RPG Interaction with Java in V5R1

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times
Before V5R1, it was possible for Java classes to interact with RPG procedures and programs. One way to communicate between Java and RPG was by using the Java Native Interface (JNI). Another way was for RPG to call Java by using the Java command RUNJVA and for Java to call RPG using the VisualAge for Java (VAJ) AS/400 Toolbox classes. Using the JNI was extremely easy for Java but was extremely difficult for RPG.

Using the RUNJVA command to call Java was straightforward but somewhat awkward because a mechanism, like a data queue, had to be used to pass back information from Java. Calling RPG from Java using the Toolbox classes required no effort on the RPG side but considerable coding on the Java side.

New in V5R1

In V5R1, it is now simple for RPG programmers to use the JNI, assuming the RPG programmer is somewhat familiar with Java. In this article, I assume you have basic knowledge of Java.

The JNI allows a Java class to declare that a method is a native method--a procedure written in a non-Java language that is native to the operating system. The most common JNI languages are C and C++, but any language supporting bound procedures can use JNI. The JNI also allows other languages to start the Java Virtual Machine (JVM) and call Java methods directly.

Using the new RPG support, RPG programmers can write native methods and call Java methods almost exactly the same way they write ordinary subprocedures and call other procedures. In fact, you can't detect that a call is to a Java method or that a subprocedure is actually a Java native method. You can only detect this information from the prototype. The daysBetween subprocedure in Figure 1 is an example of an RPG native method.

P daysBetween     B                   EXPORT
D daysBetween     PI            10I 0
D   date1                         D   CONST DATFMT(*ISO)
D   date2                         D   CONST DATFMT(*ISO)
C                   RETURN    %DIFF(date1 : date2 : *DAYS)))
P daysBetween     E

Figure 1: The daysBetween RPG subprocedure can be used as a Java method.

A new object data type has been added to RPG. You define an object by coding the type O and the CLASS(*JAVA : classname) keyword. You can't do very much with an object type. You can assign one object to another, compare one object to another for equality, and pass objects as parameters and return them from procedures and native methods.
A new form of the EXTPROC keyword takes three parameters:

  1. *JAVA
  2. The name of the Java class (for example, 'java.lang.String' or 'MyClass')
  3. The name of the Java method (for example, 'getBytes' or 'myMethod')


If the method is a class constructor, the special word *CONSTRUCTOR is used. If the method is a static method, the STATIC keyword is used for the prototype.

Calling RPG from Java

Figure 2 shows a small Java class. The purpose of this class is to allow Java to use some of the date-time-timestamp functions of RPG.

class Dtz
{
   static
   {
      System.loadLibrary ("DTZSRV");
   }
   String dtzType = "DATE";

   native String getCurDtz ();
   static native boolean chkDtzType (byte dtzType[]);

   Dtz(String dtz) throws Exception
   {
      if (!chkDtzType(dtz.getBytes()))
      {
         throw new Exception("Bad DTZ type");
      }
      else
      {
         this.dtzType = dtz;
      }
   }

   byte[] getDtzType()
   {
      return dtzType.getBytes();
   }

   public static void main (String args[])
   {
      Dtz d;

      // create a new Dtz
      try
      {
         d = new Dtz(args[0]);
      }
      catch (Exception e)
      {
         System.out.println (e.toString());
         return;
      }

      // get the current date, time or timestamp
      System.out.println (d.getCurDtz());
   }

}


Figure 2: This Java class loads an RPG service program.

The first thing in the class is a static block that uses the loadLibrary method from the System class to locate the service program containing the RPG native methods. When the Java class is run, the service program DTZSRV must be found in the library list. The rest of the class is straightforward, except the two native methods getCurDtz and chkDtzType. These are native methods, indicated by the native keyword. Native methods have no method body. When a native method is invoked by a Java class, the JNI is used to make a call outside of Java to a procedure in the service program. The Java class calls the native method chkDtzType in the constructor, and it calls the native method getCurDtz in main.

Figure 3 shows an RPG module containing the native methods used by the Java class.

     H thread(*serialize) nomain

     D DtzClass        C                   'Dtz'
     D StringClass     C                   'java.lang.String'

     D getCurDtz       PR              O   class(*java : StringClass)
     D                                     extproc(*JAVA
     D                                           : DtzClass
     D                                           : 'getCurDtz')

     D chkDtzType      PR              N   extproc(*JAVA
     D                                           : DtzClass
     D                                           : 'chkDtzType')
     D                                     static
     D   dtzType                     20A   const varying

     D getDtzType      PR            20A   extproc(*JAVA
     D                                           : DtzClass
     D                                           : 'getDtzType')

     D newString       PR              O   extproc(*JAVA
     D                                           : StringClass
     D                                           : *constructor)
     D   value                      200A   const varying


     P getCurDtz       B                   export
     D getCurDtz       PI              O   class(*java : StringClass)
     D type            S                   like(getDtzType)
     D retval          S             26A   varying
      /free
          type = getDtzType(%this);
          select;
             when type = 'DATE';
                eval retval = %CHAR(%date());
             when type = 'TIME';
                eval retval = %CHAR(%time());
             when type = 'TIMESTAMP';
                eval retval = %CHAR(%timestamp());
          endsl;
          return newString(retval);
      /end-free
     P getCurDtz       E



     P chkDtzType      B                   export
     D chkDtzType      PI              N   static
     D   dtzType                     20A   const varying
      /free
          return  dtzType = 'DATE'
              or  dtzType = 'TIME'
              or  dtzType = 'TIMESTAMP';
      /end-free
     P chkDtzType      E

Figure 3: This RPG module interacts with a Java class.

Notice the THREAD(*SERIALIZE) keyword. This keyword should always be used when RPG is interacting with Java because Java uses threads, so any code called by Java should be threadsafe. (Note that coding THREAD(*SERIALIZE) does not guarantee thread safety, but without it, your RPG code is dangerously thread-unsafe.) This source would be used to create the service program DTZSRV. If you use binder language when creating your service program, use DSPMOD to see exactly what names are exported from the module. The names will not be simply the method names; instead, they will be in the form Java_classname_methodname. These are the names you must code in your binder language. For example, native method getCurDtz in class Dtz will be exported from the module as Java_Dtz_getCurDtz.

This module uses two different Java classes: your own Dtz class and the Java String class. The RPG module defines prototypes both for the native methods and for any other Java methods it needs. Notice there is no special keyword to indicate that a Java method is a native method. When RPG finds a subprocedure definition for a Java-method prototype, it knows that the subprocedure is really a native method.

RPG programmers have several choices when they want to pass or receive character parameters from Java. To make it very simple on the Java side, the Java side can use String objects. This means that the RPG side must call the String.getBytes method to retrieve the string data, and it must call the String constructor to return string data. This is how the return value from getCurDtz method is handled. The Java method can use the returned value directly. Another possibility is to define the character data as alpha or Universal Multiple-Octet Coded Character Set-2 (UCS-2) data in the RPG module and to define it as an array of byte or array of char in the Java class. This is how the parameter for chkDtzBytes is handled. When defining character or UCS-2 data in RPG, it is usually a good idea to use the VARYING keyword or OPTIONS(*VARSIZE), since Java does not have any notion of fixed-length strings. However, there may be cases when you know that a particular string will always be 10 bytes long. In that case, 10A is fine.

Since getCurDtz is not a static method, it is working on behalf of a specific Dtz object. The first thing getCurDtz has to determine is whether the object is representing a date, time, or timestamp. It does this by calling the getDtzType method. The prototype for this method has no parameters, but since it is an instance method, an object instance must be passed as the first parameter. RPG must pass the same instance that it is working on. To get the object instance, RPG uses the new %THIS built-in function. This built-in function is only valid in non-static native methods.

When getCurDtz has calculated the value it wants to return, it must then create a Java String object. It does this by calling the String constructor, called newString in this module.

The chkDtzType method is very straightforward. Notice that the return value is defined as Boolean in the Java class and defined as an indicator in the RPG module. See Figure 4 for a table of type equivalents between RPG and Java. When you are defining prototypes for Java methods, you must be careful to match RPG types correctly to Java types.

Java Type
RPG Type(s)
Boolean
indicator
byte
1A

3I 0
byte[]
 nA

 nA   VARYING

 3I 0 DIM(x)

 1A   DIM(x)

  D   any format

  T   any format

  Z
char
 1C
char[]
 nC

 1C   DIM(x)
short
 5I 0
int
10I 0
long
20I 0
float
 4F
double
 8F
Object of any class
 O    CLASS(*JAVA:'classname')
Array of any type
type  DIM(x)
Byte data in Java can be either numeric data or character data. When it is character data, the character representation is ASCII. With RPG IV, on the AS/400, the character representation is EBCDIC. When RPG uses the alphanumeric (A) type for the Java byte type, RPG performs translation between ASCII and EBCDIC. When the RPG uses the 1 byte integer type for the Java byte type, RPG does not perform this translation.

Figure 4: RPG and Java use different names for the same data types.

Calling Java from RPG

Calling a Java method from RPG is no different from making any other prototyped call, with one exception: When you call an instance method (a nonstatic method), you must provide the instance that the method is to use. In RPG, the instance is passed as the first parameter. In Java, you code obj.method(parm1,parm2). In RPG, you code method(obj:parm1:parm2). This extra parameter does not appear in the prototype (PR) or the procedure interface (PI). For example, in Figure 5, the prototype for getDtzType has no parameters, but the call to getDtzType has one parameter.

      // methods for java.lang.String
     D StringClass     C                   'java.lang.String'

      // public byte[] getBytes()
     D stringValue     PR           200A   varying
     D                                     extproc(*JAVA
     D                                           : StringClass
     D                                           : 'getBytes')

      // methods for java.math.BigDecimal
     D DecimalClass    C                   'java.math.BigDecimal'

      // public static BigDecimal valueOf(long val, int scale)
     D getBigDecimal   PR              O   extproc(*JAVA
     D                                           : DecimalClass
     D                                           : 'valueOf')
     D                                     static
     D   numValue                    20I 0 value
     D   scale                       10I 0 value

      // public BigDecimal multiply (BigDecimal val)
     D bdMult          PR              O   extproc(*JAVA
     D                                           : DecimalClass
     D                                           : 'multiply')
     D   multiplier                    O   class(*java : DecimalClass)
     D                                     const

      // public String toString ()
     D bdToString      PR              O   extproc(*JAVA
     D                                           : DecimalClass
     D                                           : 'toString')

      // variables used in the calculation
     D num1            S                   like(newBigDecimal)
     D num2            S                   like(newBigDecimal)
     D result          S            200A   varying

      /free
          // set num1 to 1111122222.3333344444
          num1 = getBigDecimal (11111222223333344444 : 10);

          // set num2 to 999998888877777.66666
          num2 = getBigDecimal (99999888887777766666 : 5);

          // calculate num1 * num2 * num2 and place the 
          // result of the calculation in an RPG varying length
          // string
          num1 = bdMult (num1 : num2);
          num1 = bdMult (num1 : num2);
          result = stringValue (toString (num1));
      /end-free


Figure 5: An RPG program that needs more than 30 digits of precision can use Java's BigDecimal class.

Figure 5 shows an example of RPG using Java's BigDecimal class to do a numeric calculation that has a result with more than 30 digits. This calculation would require the use of a floating-point result in RPG, but the result would not be exact. Floating-point variables only have about 17 digits of precision. The BigDecimal class does not have any limit on precision.

Figure 5 uses two classes: String and BigDecimal. The BigDecimal class has a static method that creates a BigDecimal object from a long value and a scale. This method is used to create two BigDecimal objects.

Then the multiply method is used to multiply the values. Notice that the prototype for multiply has only one parameter, while the call has two parameters. Since multiply is not a static method, the first parameter is the object instance for the method to work with.

Finally, the toString method of BigDecimal is used to get the String representation of the result of the multiplication. To get the actual value of this string, the getBytes method of the String class is used. Again, since toString and getBytes are instance methods, an extra parameter must be passed on each call.

Calling Your Own Java Classes from RPG

When the first Java method is called, RPG will start the JVM if it has not already been started. RPG uses the CLASSPATH environment variable when it starts the JVM, so make sure you have set the environment variable using ADDENVAR before the JVM is created if you want to use your own classes:

ADDENVVAR CLASSPATH '/home/bmorris'

Additional Required Coding to Call Java

The new Java support makes it very easy to call Java methods. However, Java is not the same as other ILE languages, and to use the JNI correctly, there is a little additional programming you must do.

For example, when you call Java from an ordinary RPG procedure (not from a native method), any objects you create are not subject to Java's garbage collection until you explicitly free them. Conversely, when you call a native method from Java, any objects that are created while the native method is running are destroyed when the native method returns. If you want the objects to be available to RPG later, you must prevent Java from freeing the objects. If you are calling Java from RPG, RPG will start the JVM for you if it is not already started, but it is up to you to end the JVM.

You can read about this additional coding in the Java chapter of the V5R1 ILE RPG Programmer's Guide. This guide tells you what you have to do and has sample procedures that show how to do it. You will also find it worthwhile to read about JNI programming at http://java.sun.com/docs/books/tutorial/native1.1/index.html.

What RPG Doesn't Support

The RPG support only allows you to call Java methods. The JNI also gives you access to the data members (fields) in a Java class. If you want to do more JNI programming than RPG allows, you can do it yourself by calling all the JNI functions directly, using the /COPY file JNI in file QSYSINC/QRPGLESRC. There is a small example of this in the V5R1 ILE RPG Programmer's Guide.

Barbara Morris joined IBM in 1989 after graduating from the University of Alberta with a degree in computing science. Within IBM, she has always worked on the RPG Compiler team. You can contact Barbara at This email address is being protected from spambots. You need JavaScript enabled to view it..





BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$0.00 Raised:
$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: