Turn conceptual Java properties into definitive, concrete attributes.
When working with RPG in different environments, such as production and test, you will most likely be working with different library lists and using different versions of programs and files. To provide a sanity check for yourself, you will want to ensure that you're using the correct programs and files by validating the objects that are being used by the job. This article shows you some methods that I use to verify similar Java attributes when using Java with RPG, such as the currently running version of JVM and the class path that is being used.
I recently had the opportunity to work with some very talented and innovative RPG and Java programmers in North Carolina who were working together to implement the programming methodologies that are presented in my book Advanced Integrated RPG, which covers various ways to implement open-source Java functionality within RPG programs. During my visit, we discussed some issues relating to working with Java within RPG, which also matched some topics that are actively being discussed in the forums. This article attempts to clarify some of these topics.
Checking the Java Virtual Machine (JVM) Version in Qshell
One quick and easy way to see which version of Java is being used is to execute Java from the Qshell command line (just as you would from a Windows DOS or Linux command prompt) by passing in the "-version" parameter.
You can enter Qshell by typing strqsh. At the Qshell command line, you then enter "java -version" to see something similar to the following (your results may vary, depending upon the version you're running on your system):
Figure 1: Determine which version of Java you're using. (Click images to enlarge.)
Identifying Multiple JVMs
For the purpose of identifying that a JVM exists on your IBM i and determining, which version it is, using Qshell does the job. But what if you have multiple JVMs on your machine?
You can see which JVMs are installed on your IBM i by using the go licpgm command. When you display the licensed programs on your system, you can find all of the Java Development Kits (JDKs) that are installed (your list may look different, depending upon what is installed on your system):
Figure 2: Determine which licensed programs you have installed.
You may assume that the latest Java version is the one being used, but that's not always the case. You could check the version of Java in Qshell, but that's a different environment. How do you know that is the same one that is being used by RPG? And if you do have multiple JVM versions on your system and you're attempting to override one to use another one that is not the default, how do you know that the settings you've applied are actually being used? The best way would be to simply ask the JVM.
Java System Properties
Java has a System class that has various facilities that include access to the properties of the JVM and environment variables. To access the current properties, you can use the getProperty method, along with a string parameter identifying the property that you are interested in.
One of the many packages included with the JVM is the java.lang package. Contained in that package is the System class. The System class has a few methods that you can use to retrieve the properties. Figure 3 shows a partial JavaDoc listing of the System property methods. (Note: You can find the complete online JavaDocs for the System class by clicking here.)
Figure 3: This is a partial listing of the System property methods.
The list of available properties are contained within the JavaDocs for the System class and can be found by clicking here. Here is a partial list to demonstrate some useful properties that you may be interested in:
Useful Properties |
|
Key |
Description |
java.version |
Java Runtime Environment version |
java.vendor |
Java Runtime Environment vendor |
java.home |
Java installation directory |
java.class.path |
Java class path |
os.name |
Operating system name |
os.arch |
Operating system architecture |
os.version |
Operating system version |
user.name |
User's account name |
user.home |
User's home directory |
user.dir |
User's current working directory |
The two methods I have displayed above, getProperties and getProperty, will return the same values in different ways. To stay focused on the objective, we will use the getProperty method, which allows us to specify a single property that we are interested in and returns a string that we can work with. If you were to use the getProperties method, you would receive all of the properties in a Properties object.
To enable RPG to access the Java method, we will create a prototype to access the getProperty method of the java.lang.System class, as follows:
D System_getProperty...
D PR like(jString)
D ExtProc(*JAVA
D :'java.lang.System'
D :'getProperty')
D static
D argString like(jString)
If you refer to the JavaDocs above, you will see that the getProperty method will accept a String object as the parameter and will also return a String object. You can also see in the JavaDocs that the method is static, so we will need to specify that on the prototype.
Because we are working with RPG, which uses EBCDIC, we will need to handle the conversions to ASCII for the JVM to be able to understand the bytes of data we're sending. For this situation, I like to put an RPG wrapper around the call to the prototyped Java method that will handle the character conversions. This way, I can code it once and make it as painless as possible for future reuse, as follows:
P******************************************************************
P* Air_getSystemProperty(): Gets the System.getProperty
P******************************************************************
P Air_getSystemProperty...
P B EXPORT
D Air_getSystemProperty...
D PI 65535A varying
D argBytes 65535A const varying options(*varsize)
D svString S like(jString)
D svResult S like(jString)
D svBytes S 65535A varying
/free
svString = new_String(%trim(argBytes));
svResult = System_getProperty(svString);
svBytes = String_getBytes(svResult);
return svBytes;
/end-free
P E
Here is what the procedure is doing:
- The incoming EBCDIC bytes are converted into ASCII when the String object is constructed with the call to new_String.
- Then, the resulting String object is passed as the parameter to the System_getProperty prototype for the Java method, which will return ASCII bytes.
- Finally, the ASCII byte results are converted to EBCDIC for use in RPG.
The Character set conversions can be a pain, which is why I like to wrap them up into procedures. Plus, doing so gives you the modular design to enhance your procedure later on to possibly add exception handling.
The Code
With the prototype defined, we can now write some code to use this new method. I wrote an article called "Advanced Integrated RPG: Using Java with RPG" that covers some of the details on how to use the Java String Object within RPG and how to start and stop the JVM. So I'll reuse that code in our example.
When using the getProperty method, all you have to do is pass in the string to indicate the system property that you're interested in. So, for our example, we will get the version of Java that is currently being used by RPG, the class path, the operating system name, the operating system version, and the user name. And because we wrapped our Java calls inside of a procedure that handles our character conversions, we can simply pass in our strings as straight text in our code:
/free
// Call getJNIEnv() to:
// - Ensure First Three File Descriptors are open
// - Start JVM, if not started
// - Attach to JVM, if already started
getJNIEnv();
// Java Version
displayBytes = 'Java Version: '
+ Air_getSystemProperty('java.version');
DSPLY displayBytes;
// Java Class Path
displayBytes = 'Java ClassPath: '
+ Air_getSystemProperty('java.class.path');
DSPLY displayBytes;
// Operating System Name
displayBytes = 'Operating System Name: '
+ Air_getSystemProperty('os.name');
DSPLY displayBytes;
// Operating System Version
displayBytes = 'Operating System Version: '
+ Air_getSystemProperty('os.version');
DSPLY displayBytes;
// User Name
displayBytes = 'User Name: '
+ Air_getSystemProperty('user.name');
DSPLY displayBytes;
*inlr = *ON;
/end-free
Running the program would generate results similar to the following:
Figure 4: Show the system properties.
You can see that RPG is using Java Version 1.4.2 on OS/400 V5R3M0 (your results may vary, based on the system you're running on). Now you know exactly which version of the JVM is being used within your RPG code on your system.
Static Note
I want to point out something about static methods that could be especially helpful to anyone who is new to Java and has been trying this out with RPG. You may have noticed that I did not need to create an instance of the System class in order to access its methods. This is because it is a static method of the class. This means that you do not need to create an instance because the state/value of the method applies to all instances of the class and is not dependent upon an instance to be created; all you have to do is call the method and you will get the value you're looking for.
If you look on the left side of the JavaDocs, you will see the static keyword specified. When you create the prototype for the method, you need to indicate that it is static.
Adding Java to Your RPG Toolbox
As Joe Pluta pointed out in one of his recent articles, "Choosing a Web Language? Choose Wisely," Android is now a viable option in the mobile computing market, and it's my latest avenue of programming exploration as well. This now gives Java more relevance when you're deciding which Web language to use on your IBM i. Think about it: you could really integrate Java with RPG, run Java right on your IBM i without any dependence upon an outside server, and also use the very same language to write your mobile applications. You might want to add that to your pros versus cons list when you are making your decision.
Download the Code
For the intentions of providing an autonomous working example, I have placed all of the prototypes and procedures into the same code source. But, for modular coding reuse, I recommend putting the procedures into a separate file to be copied into the source. And I would create a service program with the procedures. You can download the code by clicking here.
At this point, I do not encourage the use of fixed-formatted programming and would not want to convolute the service programs, so I did not provide the procedure in fixed-format. But, for the purpose of accessing the service programs from existing fixed-formatted programs, I did provide an example of accessing the procedures with some fixed-formatted code.
LATEST COMMENTS
MC Press Online