Introduction to Java and RPG
The Java programming language is a high-level object-oriented language developed by Sun Microsystems. Java programs can be developed using the VisualAge® for Java component of WebSphere Development Studio for iSeries.
In object-oriented programming, a ″method″ is a programmed procedure that is defined as part of a ″class″, which is a collection of methods and variables. Java methods can be called from your RPG program. While most Java methods are written in Java, a method can also be written in another high-level language, such as RPG. This is known as a ″native method″. This section includes information on calling Java methods from RPG and on writing RPG native methods.
The Object Data Type and CLASS Keyword
Fields that can store objects are declared using the O data type. To declare a field of type O, code O in column 40 of the D-specification and use the CLASS keyword to provide the class of the object. The CLASS keyword accepts two parameters:
*JAVA identifies the object as a Java object.Class_name specifies the class of the object. It must be a character literal or named constant, and the class name must be fully qualified. The class name is case sensitive.
For example, to declare a field that will hold an object of type BigDecimal:D bdnum S O CLASS(*JAVA:’java.math.BigDecimal’)
To declare a field that will hold an object of type String:D string S O CLASS(*JAVA:’java.lang.String’)
Note that both class names are fully qualified and that their case exactly matches that of the Java class.
Fields of type O cannot be defined as subfields of data structures. It is possible to have arrays of type O fields, but pre-runtime and compile-time tables and arrays of type O are not allowed.
Prototyping Java Methods
Like subprocedures, Java methods must be prototyped in order to call them correctly. The ILE RPG compiler must know the name of the method, the class it belongs to, the data types of the parameters and the data type of the returned value (if any), and whether or not the method is a static method.
The extended EXTPROC keyword can be used to specify the name of the method and the class it belongs to. When prototyping a Java method, the expected format of the EXTPROC keyword is:EXTPROC(*JAVA:class_name:method_name)
Both the class name and the method name must be character constants. The class name must be a fully qualified Java class name and is case sensitive. The method name must be the name of the method to be called, and is case sensitive.
Use *JAVA when creating a prototype for either a method written in Java or a native method written in RPG. Use the STATIC keyword to indicate that a method is static.
Java and RPG Definitions and Data Types:
The data types of the parameters and the returned value of the method are specified in the same way as they are when prototyping a subprocedure, but the data types actually map to Java data types. The following table shows the mappings of ILE RPG data types to and from Java data types.
Zoned, Packed, Binary, and Unsigned data types are not available in Java. If you pass a Zoned, Packed, Binary, or Unsigned field as a parameter, the compiler will do the appropriate conversion, but this may result in truncation and/or loss of precision.
When calling a method, the compiler will accept arrays as parameters only if the parameter is prototyped using the DIM keyword.
If the return value or a parameter of a method is an object, you must provide the class of the object by coding the CLASS keyword on the prototype. The class name specified will be that of the object being returned or the parameter being passed. (Use the EXTPROC keyword to specify the class of the method being called.)
If the method being called is a static method, then you must specify the STATIC keyword on the prototype. If the method is a constructor, you must specify *CONSTRUCTOR as the name of the method.
In Java, the following data types can only be passed by value:
Parameters of these types must have the VALUE keyword specified for them on the prototype.
Note that objects can only be passed by reference. The VALUE keyword cannot be specified with type O. Since arrays are seen by Java as objects, parameters mapping to arrays must also be passed by reference. This includes character and byte arrays. The CONST keyword can be used.
Examples of Prototyping Java Methods: This section presents some examples of proto typing Java methods.
Example:The Java Integer class contains a static method called toString, which accepts an int parameter, and returns a String object. It is declared in Java as follows:static String Integer.toString(int)
This method would be prototyped as follows:
The EXTPROC keyword identifies the method as a Java method. It also indicates that the method name is ’toString’, and that it is found in class ’java.lang.Integer’. The O in column 40 and the CLASS keyword tell the compiler that the method returns an object, and the class of that object is ’java.lang.String’.
The STATIC keyword indicates that the method is a static method, meaning that an Integer object is not required to call the method.
The data type of the parameter is specified as 10I, which maps to the Java int data type. Because the parameter is an int, it must be passed by value, and the VALUE keyword is required.
Example: The Java Integer class contains a static method called getInteger, which accepts String and Integer objects as parameters, and returns an Integer object. It is declared in Java as follows:
static Integer Integer.getInteger(String, Integer)
This method would be prototyped as follows:
This method accepts two objects as parameters. O is coded in column 40 of the D-specification and the CLASS keyword specifies the class of each object parameter. Because both parameters are input-only, the CONST keyword is specified.
Example: The Java Integer class contains a method called shortValue, which returns the short representation of the Integer object used to invoke the method. It is declared in Java as follows:short shortValue()
This method would be prototyped as follows:
The STATIC keyword is not specified because the method is not a static method. The method takes no parameters, so none are coded. When you call this method, you will specify the Integer instance as the first parameter. The returned value is specified as 5I, which maps to the Java short data type.
Example: The Java Integer class contains a method called equals, which accepts an Object as parameter and returns a boolean. It is declared in Java as follows:boolean equals(Object)
This method would be prototyped as follows:
The returned value is specified as N, which maps to the Java boolean data type. Because this is not a static method, a call to this method will have two parameters with the instance parameter coded first.
Calling Java Methods from ILE RPG
This section describes how to call Java methods from ILE RPG programs.
If the method is not a static method, then it is called an ″instance method″ and an object instance must be coded as an extra first parameter in order to call the method. For example, if an instance method is prototyped with one parameter, you must call it with two parameters, the first being the instance parameter.
The following steps describe the call from ILE RPG to a Java method:
CAUTION: Since Java uses threads, the THREAD(*SERIALIZE) keyword must be coded in all modules that interact with Java. RPG relies heavily on static storage even in subprocedures that apparently only use automatic storage. THREAD(*SERIALIZE) is necessary to ensure the correct handling of this static storage. This applies not only to modules that contain calls to Java methods, but also to any modules that might be called during interactions with Java. See “Additional RPG Coding for Using Java” for more information about the various JNI functions.
Example In this example, the goal is to add two BigDecimal values together. In order to do this, two BigDecimal objects must be instantiated by calling the constructor for the BigDecimal class, fields must be declared to store the BigDecimal objects, and the add() method in the BigDecimal class must be called.
RPG Code Example Calling BigDecimal Java Class
Here is the code that does the call.
This example shows how to perform a TRIM in Java by using the trim() method as an alternative to the ILE RPG %TRIM built-in function. The trim() method in the String class is not a static method, so a String object is needed in order to call it.
RPG Code Example Using trim() Java Method
The call is coded as follows:
RPG Call to the String constructor
Static methods are called in the same way, except that an object is not required to make a call. If the getBytes() method above was static, the call would look like the example below.
C EVAL fld = getBytes()
If the method does not return a value, use the CALLP operation code.
In order to call a non-static method, an object is required. The class of the object must be the same as the class containing the method. You may already have an object available, but you may sometimes need to instantiate a new object. You do this by calling a class constructor. A class constructor is neither a static method nor an instance method, and therefore it does not need an instance parameter. The special method name *CONSTRUCTOR is used when prototyping a constructor.
For example, class BigDecimal has a constructor that accepts a float parameter.
This constructor would be prototyped as follows:
Note that the parameter must be passed by value because it maps to the Java float data type.
You would call this constructor like this:
The class of the returned object is the same as the class of the constructor itself, so the CLASS keyword is redundant for a constructor, but it may be coded.
Calling methods in your own classes
When you use your own Java classes, the class that you specify in the EXTPROC and CLASS keywords is simply the name of the class. If the class is part of a package, you include the package information in the keywords. For example, consider the following two classes:
If the Simple class file is /home/myclasses/Simple.class, you would specify the directory /home/myclasses in your CLASSPATH environment variable, and you would specify ’Simple’ as the class name in your RPG keywords.
If the PkgClass class file is /home/mypackages/MyPkg/PkgClass.class, you would specify the directory /home/mypackages (the directory containing the package) in your CLASSPATH environment variable, and you would specify ’MyPkg.PkgClass’ (the package-qualified Java class) as the class name in your RPG keywords.
The class name for your RPG keywords is the same name as you would specify in your import statements in your Java classes. You use the CLASSPATH environment variable to specify the location of the class files, or the location of the directory containing the package.
Note: Note: If you have classes in a jar file, you specify the jar file itself in your classpath.
===> ADDENVVAR CLASSPATH ’/home /myclasses: /home /mypackages: /home /myjarfiles /j1.jar’
Creating an RPG prototype for a Java method in a package
Controlling how the Java Virtual Machine is set up
When RPG starts the Java Virtual Machine (JVM), there are several options that control how the JVM is started. See the Java System Properties section in the iSeries Information Center.
To specify options in the QIBM_RPG_JAVA_PROPERTIES environment variable, you code the options in a string, one after the other, separated by any character that does not appear in any of the options. Then you end the string with the separator character. For example, if you want to specify the options java.version=1.4 os400.stderr=file:stderr.txt then you would add the environment variable using the following command:
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) VALUE(’-Djava.version=1.4;-Dos400. stderr=file :stderr.txt;’)
If the options string is not valid, Java may reject one of the options. Message JVAB55A will appear in the joblog indicating which option was not valid. If this happens, RPG will try to start the JVM again without any of the options, but still including the java.class.path option if it came from the CLASSPATH environment variable
RPG Native Methods
To define an RPG native method, you code the prototype the same way as you would code the prototype for an ordinary Java method. Then, you write the RPG subprocedure normally. You must code the EXPORT keyword on the Procedure-Begin Specification for the native method.
You must have your native methods in a service program in your library list. In your Java class that is calling your native methods, you must have a static statement like this:
This will enable Java to find your native methods. Aside from adding *JAVA and the class to the EXTPROC keyword for the prototype of a native method, you write your native method like any subprocedure.This is an example of a Java class that calls a native method.
CAUTION: If you are using environment variables to control how the JVM is started, you must be sure that the environment variables exist in the job before any RPG programs call Java methods. If you use ADDENVVAR LEVEL(*SYS), the environment variable will be added at the system level, and by default, every job will start with that environment variable set. If you do this, be sure that the classpath includes all the directories containing the Java classes that may be needed by any application on the system.
Java Class Calling a Native Method
This is a prototype of an RPG native method.
RPG Native Method Prototype
The native method itself is coded just like any subprocedure. This is an example of a native method coded in RPG.
Native Method Coded in RPG
Java calls your service program from the default activation group. If your service program is created with activation group *CALLER, it will run in the default activation group. This can sometimes cause problems:
If you create any Java objects in your native methods, by default they will be destroyed by Java when the native method returns. If you want the object to be available after the native method returns (for example, if you want to use it from another native method later), then you must tell Java that you want to make a global reference, by calling the JNI wrapper procedure getNewGlobalRef . When you are finished with the global reference, you will call JNI wrapper procedure free Global Ref, so Java can reclaim the object. See “Telling Java you want an object to be permanent” and “Telling Java you are finished with a permanent object” for more information about these wrapper procedures.
If your RPG native method ends abnormally with an unhandled exception, the RPG compiler will throw an exception to Java. The exception is of class java.lang.Exception, and has the form RPG nnnnn, where nnnnn is the RPG status code.
Getting the Instance Parameter in Non-Static Native Methods
When a non-static native method is called, one of the parameters that Java passes to the native method is the object that the method applies to. This is called the ″instance parameter″, referred to as ″this″ in a Java method. Within the native method itself, you can use the built-in function %THIS to get the instance parameter. You do not code this parameter in your Procedure Interface.
Passing Character Parameters from Java to Native Methods
You have two choices when dealing with character parameters:
Using String Objects in RPG: If you have a String object in your RPG code, you can retrieve its length and contents using the code.
Retrieving String object length and contents from Java
You can define the returned value from the getBytes method as character data of any length, either varying or non-varying, choosing the length based on your own knowledge of the length of data in the Java String. You can also define the return value as a Date, Time or Timestamp, if you are sure that the String object will have the correct format.
Alternately, you can retrieve the string value as a UCS-2 value, by calling the getChars method instead of getBytes.
Coding Errors when calling Java from RPG
Failure to free Java resources
When you create a Java object by calling a constructor, or by calling a method that returns an object, that object will remain in existence until it is freed. It is freed when:
If the RPG procedure calling the Java method is not itself an RPG native method, and the RPG procedure does not take care to free objects it has created, then the job may eventually be unable to create any more objects.
Consider the following code fragment:
It appears that this code is taking care to free the object, but in fact this code creates two objects. The first object is created by the called to newString(), and the second is created by the call to trim(). Here are two ways to correct this code fragment:
Another problem can be created by calling Java methods as parameters to other Java methods. In the following example, the program is creating a BigDecimal object from the constructor that takes a String parameter:
The problem with this code is that a String object has been created for the parameter, but it can never be freed by the RPG procedure. This problem can be corrected by calling begin Obj Group() before the RPG code that calls Java and calling endObjGroup() after, or by coding as follows:
Using objects that no longer exist
If you have static Object variables in your native method (STATIC keyword on the definition), or your native method uses static global Object variables (variables declared in the main source section), then the Object variables will retain their values between calls to the native method. However, by default, Java will free any objects created during a call to a native method. (“Additional RPG Coding for Using Java” see how to prevent Java from freeing objects.)
An RPG ″Object″ is really a numeric object reference. When a Java object is freed, the numeric object reference can be reused. If the RPG native method refers to a static Object variable that has not been explicitly protected from being freed, one of two things can happen:
To prevent problems with attempting to reuse objects illegally, the RPG programmer may do one or more of the following:
Additional RPG Coding for Using Java
When you are using ILE RPG with Java, there are some functions normally handled by Java that must be handled by your RPG code. The RPG compiler takes care of some of these for you, but you must handle some of them yourself. This section shows you some sample RPG wrappers to do this work, explains how and when to call them, and suggests how to handle JNI exceptions.
The module that you create to hold these JNI wrapper functions should begin with the following statements:H =thread(*serialize) H nomain /define OS400_JVM_12 /copy qsysinc/qrpglesrc,jni
The following RPG wrappers for JNI functions are described:
Telling Java to free several objects at once
You can free many local references at once by calling the JNI function PushLocalFrame before a section of RPG code that uses Java and then calling PopLocalFrame at the end of the section of RPG code. When you call PopLocalFrame, any local references created since the call to PushLocalFrame will be freed. For more information about the parameters to these JNI functions,
Note: You need the JNI environment pointer (described in “Obtaining the JNI environment pointer”) to call this wrapper.
Telling Java you are finished with a temporary object
If you have created an object using a Java constructor, or if you have called a Java method that returned an object to you, this object will only be available to be destroyed by Java’s garbage collection when it knows you do not need the object any more. This will happen for a native method when the native method returns, but it will never happen for a non-native RPG procedure, unless you explicitly inform Java that you no longer need the object. You do this by calling the RPG wrapper procedure freeLocalRef.
It contains the sample source code for freeLocalRef.
Source Code for freeLocalRef
Note: You need the JNI environment pointer (described in “Obtaining the JNI environment pointer”) to call this wrapper.
Telling Java you want an object to be permanent
If you have a reference to a Java object that was either passed to you as a parameter or was created by calling a Java method or constructor, and you want to use that object after your native method returns, you must tell Java that you want the object to be permanent, or ″global″. Do this by calling the RPG wrapper procedure getNewGlobalRef and saving the result in a global variable.
It contains the sample source code for getNewGlobalRef.
Source Code for getNewGlobalRef
Telling Java you are finished with a permanent object
If you have created a global reference, and you know that you no longer need this object, then you should tell Java that as far as you are concerned, the object can be destroyed when Java next performs its garbage collection. (The object will only be destroyed if there are no other global references to it, and if there are no other references within Java itself.) To tell Java that you no longer need the reference to the object, call the RPG wrapper procedure freeGlobalRef . CALLP freeGlobalRef (JNIEnv_P : globalString);
This contains sample source code for freeGlobalRef.
Note: You need the JNI environment pointer (described in “Obtaining the JNI environment pointer” below) to call this wrapper.
Creating the Java Virtual Machine (JVM)
If the JVM has not already been created when your RPG code is ready to call a Java method, RPG will create the JVM for you, using the default classpath plus the classpath in your CLASSPATH environment variable. However, if you want to create the JVM yourself.
Obtaining the JNI environment pointer
If you need to call any JNI functions,use the /COPY file JNI from QSYSINC /QRPGLESRC. Most of the JNI functions are called through a procedure pointer. The procedure pointers are part of a data structure that it itself based on a pointer called the ″JNI environment pointer″. This pointer is called JNIEnv_P in the JNI /COPY file. To obtain this pointer, call the JNI wrapper procedure getJniEnv. EVAL JNIEnv_P = getJniEnv();
This contains sample source code for getJniEnv.
Handling JNI Exceptions
In ILE RPG, an exception causes an exception message to be signaled. Programs do not need to check explicitly for exceptions; instead, you can code exception handlers to get control when an exception occurs. You only have to handle JNI exceptions yourself when you are making your own JNI calls. When a call to a JNI function results in an unhandled Java exception, there is no accompanying exception message. Instead, the JNI programmer must check whether an exception occurred after each call to a JNI function.
This is done by calling the ExceptionOccurred JNI function, which returns a Java Exception object (or the Java null object which has a value of 0 in the JNI). Once you have determined that an exception has occurred, the only JNI calls you can make are ExceptionClear and ExceptionDescribe. After you have called ExceptionClear, you are free to make JNI calls again. If you make a non-exception JNI call before calling ExceptionClear, the exception will disappear, and you will not be able to get any further details. RPG always converts a JNI exception into an RPG exception (it signals one of the RNX030x messages, depending on the RPG function that was being done at the time).
Tip! You may want to include this type of exception-handling code in your versions of the JNI wrapper procedures above.
Additional Considerations Common Runtime Errors
The compiler will not attempt to resolve classes at compile time. If a class cannot be located at run time, a runtime error will occur. It will indicate that an Unresolved Link Exception object was received from the Java environment.
The compiler does no type checking of parameters at compile time. If there is a conflict between the prototype and the method being called, an error will be received at run time.
A Java object is viewed as an object reference in RPG. This object reference is an integer value, which behaves like a pointer. Normal object references are positive values, assigned in increasing order from 1. Global references, which can be created using JNI function NewGlobalRef , are negative values. These values are assigned in increasing order from the smallest negative number (-2147483647).
Normally, these values are not visible within the RPG code. However, this information may be useful when debugging RPG code.
Creating String objects in RPG
If you need a String object to pass to a Java method, you can create it like this:
Getting information about exceptions thrown by called Java methods
When RPG calls a Java method that ends with an exception, RPG handles the Java exception and signals escape message RNX0301. This message has the string value of the Exception, but it does not have the trace information that is normally available when Java calls a method that ends with an exception.
If you want to see the Java exception trace information, do the following:
Note: This step must be done before the JVM is started.
Note: This step must be done before the JVM is started.
Note: This step can be done at any time. To stop the exception trace being done by RPG, you can remove the environment variable, or set it to a value other than ’Y’.
Advanced JNI Coding
The RPG IV compiler support for calling Java methods and for writing RPG native methods hides almost all the JNI coding from the RPG programmer. However, RPG’s support is not necessarily the most efficient. For example, it always converts arrays between RPG and Java on calls and on entry and exit from native methods, but you may want to handle your own array conversions to improve performance.
The RPG support only gives you access to Java methods. If you want to access the fields in a class, you would have to add ″get″ and ″set″ methods to the Java class, or do JNI coding (see “Accessing Fields in Java Classes”).
Figure is an example of a JNI call in RPG.
Note that the pointers JNIEnv_P and jvalue_P are defined in the JNI /COPY file.
Converting Java Character Data
In Java, character data is ASCII rather than EBCDIC, so you will have to ensure that class names, method names, and field names are in ASCII for calls to JNI functions like FindClass. Character data that comes from Java is ASCII. To use it in your RPG program, you will probably want to convert it to EBCDIC. The RPG compiler handles these conversions for you, but if you are making the JNI calls yourself, you will have to do the conversions between ASCII and EBSDIC.
Accessing Fields in Java Classes
RPG only supports calling Java methods; it does not support accessing Java fields. Normally, fields can be accessed through ″get″ and ″set″ methods, but it is also possible to access fields using JNI calls. Here is an example showing JNI calls necessary to access the fields of a Java class or object.
Note: This example is intended to be an example of using the JNI. It is not intended to be a recommendation to access fields directly rather than using ″get″ and ″set″ methods.
Using JNI to Access Fields of Java Classes and Objects
Calling Java Methods Using the JNI Rather than RPG *JAVA Prototypes
The first three parameters are always the same:
Choose this way if you are going to call the same method many times, since it makes the method very easy to call. This expects the parameters to be passed normally. To call this JNI function, an RPG programmer would copy the CallVoidMethod prototype from the JNI /COPY file, and code additional parameters. For example,
Choose this way if you do not want to create a separate prototype for calling a method. This expects an array of jvalue structures, with each element of the array holding one parameter.This is an example of this.
Do not use this in RPG code. It expects a C construct that is extremely awkward to code in RPG.
The actual function to call depends on the type of the return value. For example, if the method returns an integer, you would use CallIntMethodA. To get the class and methodID parameters for these functions, use the FindClass and GetMethodID or GetStaticMethodID.
Note: When calling the JNI directly, the class names must be specified with a slash (/) rather than a period (.) as the separator. For example, use ’java/lang/String’ rather than ’java.lang.String’.
Calling RPG programs from Java using PCML
An RPG program or procedure can be called from Java using a Program Call Markup Language (PCML) source file that describes the parameters for the RPG program or procedure. The Java application can use PCML by constructing a ProgramCallDocument object with a reference to the PCML source file.
The ILE RPG compiler will generate PCML source for your ILE RPG program or module when you specify the PGMINFO(*PCML) compiler parameter along with the INFOSTMF compiler parameter to specify the name of an IFS output file to receive the generated PCML. For CRTBNDRPG, PCML is generated based on the contents of the *ENTRY PLIST or the Procedure Interface of the main procedure.
For CRTRPGMOD, PCML is also generated based on the Procedure Interfaces of any exported subprocedures (except Java native methods). When you use CRTRPGMOD, and create a service program, you specify the service program in your Java code using the setPath(String) method of the ProgramCallDocument class.
The following are restrictions imposed by PCML regarding parameter and return value types.
The compile will fail if you generate PCML for a program or module that violates one of the restrictions. The PCML will be generated, but it will contain error messages as comments. For example, if you use a Date field as a parameter, the PCML for that parameter might look like this:
IBM - RPG Related Interview Questions
|IBM-ILE Interview Questions||IBM Informix Interview Questions|
|IBM DB2 Interview Questions||SQL Database Interview Questions|
|IBM AIX Interview Questions||SQL Interview Questions|
|AS400 Interview Questions||DB2 SQL Programming Interview Questions|
|IBM Integration Bus Interview Questions||Synopsys Interview Questions|
|Rpgle Interview Questions|
Ibm - Rpg Tutorial
Overview Of The Rpg Iv Programming Language
Rpg Programming In Ile
Program Creation Strategies
Creating An Application Using Multiple Procedures
Using Source Files
Creating A Program With The Crtbndrpg Command
Creating A Program With The Crtrpgmod And Crtpgm
Creating A Service Program
Running A Program
Calling Programs And Procedures
Rpg And The Ebusiness World
Obtaining A Dump
General File Considerations
Accessing Database Files
Accessing Externally Attached Devices
Using Workstn Files
Example Of An Interactive Application
All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd
Wisdomjobs.com is one of the best job search sites in India.