Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed...

23
Your Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com www.Partner400.com Yet More Things You Can Do With Prototypes! Agenda Syntax Extensions Defining and using Java Objects and Methods in RPG programs Writing Java Native Methods (JNI) in RPG Further study © Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 1-2

Transcript of Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed...

Page 1: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Your Partner in AS/400 and iSeries Education

Brewing Mixed Java and RPG

Applications

Jon ParisJon.Paris @ Partner400.comwww.Partner400.com

Yet More Things You Can Do With Prototypes!

Agenda

Syntax Extensions

Defining and using Java Objects and Methods in RPG programs

Writing Java Native Methods (JNI) in RPG

Further study

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 1-2

Page 2: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

The basic support was added in V5R1But it is only in the last 12 months that usage has taken offThe "real" details are in the Programmer's Guide

Chapter 11 - "RPG and the eBusiness World"

There's a new data type to declare Objects (Type "O")The CLASS keyword identifies ...... the Class to which it belongsClass name must be proceeded by *JAVA

Class name must be fully qualifiedAnd is CASE SENSITIVE!

Unless you really enjoy typing .......Set up a single definition for each object type you will be using

And use the LIKE keyword to define each instance that you need

* This next line defines "javaString" as an Object of type StringD javaString S O CLASS(*JAVA:'java.lang.String')

* We can use that object as the basis for defining all other strings D myString S LIKE(javaString)

RPG Syntax Extensions for Java

Note that arrays of objects are allowed, but fields of type 'O' cannot be subfields of a Data Structure

It is important to understand that fields of type 'O' are NOT pointers, although they do store references to objects. As you will see if you display their content under debug, they contain a simple numeric reference.

Unlike a regular RPGIV field the object does not really exist simply because you have coded its definition in your program. The definition is simply a template. You must "instantiate" the object using its class constructor before you can reference it. Those of you familiar with Java will recognize this behavior but it may not be obvious to those who have not been exposed to the Java language. Think of the definition of the object as being like the DDS definition of a record - compiling the DDS does not place a record in the file, you must "instantiate" the record by writing it to the file.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 3-4

Page 3: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Extensions to prototyping supportNeeded to identify the Java methods to be used and their parametersExtensions to EXTPROC identify the class and method names

The special method name of *CONSTRUCTOR is used to define ............. the constructor method!

i.e. The method used to instantiate new objectsThe class and method names are Case Sensitive

If the method returns an object then the object's class must also be identified ....... with the CLASS keyword

Or through the use of the LIKE keyword as in this example

* This next line defines "aString" as an Object of type StringD aString S O LIKE(javaString)

* This is the prototype needed to instantiate a new String objectD MakeJString PR O EXTPROC(*JAVA:'java.lang.String':D *CONSTRUCTOR)D LIKE(javaString)D InitValue 256A Options(*VarSize) Const

C Eval aString = MakeJString('I'm a string!')

RPG Syntax Extensions for Java

Currently the first parameter to the *EXTPROC and CLASS keywords must be specified as *Java, but now (V5R1) that the C++ compiler is available to all AS/400 and iSeries application developers we may see greater C++ usage and hopefully the compiler will be updated to allow interfacing to C++.

Note that the method name must be fully qualified and that the special method name of *CONSTRUCTOR is used to create a new instance.

Even if you never intend to write a line of Java, there may be others in your shop who will. Also, as we will demonstrate later, you may find useful open source or other Java code that would be useful o your RPG programs.

In addition, you can use your RPG skill to write Native Methods in RPGIV to provide your Java programmers with some very powerful extensions to their Java toolkit and allow for significant code reuse. Why write it from scratch in Java using JDBC etc. when you can use your high-speed RPG code!

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 5-6

Page 4: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

A very simple (and pointless) exampleCreating a Java ObjectCalling methods on the object

A more complex exampleUsing Jakarta POI classes

Create an Excel spreadsheet!Tidying Up

RPG created objects

Creating & Using Java Objects

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 7-8

Page 5: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Creating Java Objects in RPGTo create a Java object we must do two things:

Define a data item of type Object (O)Note that this does not cause the object to exist - it is just a "template"The CLASS keyword identifies the class to which the object belongs

Create the object using the *CONSTRUCTOR method of the classThis actually allocates the storage etc. and makes it a "real" objectIt is the equivalent of using "new" in Java

H DftActGrp(*No) D EMAilAddr S 30A INZ(' [email protected]')D JEMailAddr S O CLASS(*JAVA:'java.lang.String')

D MakeJString PR O EXTPROC(*JAVA:'java.lang.String'D :*CONSTRUCTOR)D CLASS(*JAVA:'java.lang.String')D InputString 256A Options(*VarSize) VARYING CONST

>>> Additional prototypes shown on next chart <<< * Display content of EMailAddr to show leading blanksC EMailAddr DSPLY * Instantiate JEMailADDR Using EMailAddr to supply the initial valueC EVAL JEMailAddr = MakeJString(EMailAddr)

This is the complete code for the example on the previous and following pages: H DftActGrp(*No) D EMAilAddr S 30A INZ(' [email protected]') D JEMailAddr S O CLASS(*JAVA:'java.lang.String')

D MakeJString PR O EXTPROC(*JAVA:'java.lang.String': D *CONSTRUCTOR) D CLASS(*JAVA:'java.lang.String') D InputString 256A Options(*VarSize) Const Varying D TrimJString PR O EXTPROC(*JAVA:'java.lang.String': D 'trim') D Class(*Java: 'java.lang.String')

D JStringToAlpha PR 30A EXTPROC(*JAVA:'java.lang.String': D 'getBytes') * Display content of EMailAddr to show leading blanks C EMailAddr DSPLY * Instantiate JEMailADDR Using EMailAddr to supply the initial value C EVAL JEMailAddr = MakeJString(EMailAddr) * Call the trim method to strip leading and trailing blanks from the String C EVAL JEMailAddr = TrimJString(JEMailAddr) * Now convert the Java String back to a conventional RPG string C EVAL EMailAddr = JStringToAlpha(JEMailAddr) * and display the result to show that the leading blanks have disappeared C EMailAddr DSPLY

C Eval *InLr = *On

Remember that the object JEMailAddr must be intstantiated before it can be used. Simply defining it is not enough. Since the *CONSTRUCTOR method allows us to supply an initial value we can also "load" its content at the same time.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 9-10

Page 6: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

D TrimJString PR O EXTPROC(*JAVA:'java.lang.String'D :'trim') Class(*JavaD :'java.lang.String')

* Call the trim method to strip blanks from the StringC EVAL JEMailAddr = TrimJString(JEMailAddr)

The object can manipulated once it has been instantiatedFirst we will use the 'trim' methodThis removes leading and trailing spaces just as RPG's %Trim does

Note that 'trim' is an instance methodi.e. It operates on an instance of the class

So the instance must be passed as the first parameterEven though it is not specified in the prototype !

What about STATIC methods ?For STATIC methods, all parameters must be specified in the proto

Invoking Java Methods from RPG

D JStringToAlpha PR 30A EXTPROC(*JAVA:'java.lang.String'D :'getBytes')

* Convert the Java String back to a conventional RPG stringC EVAL EMailAddr = JStringToAlpha(JEMailAddr)

* Display the result to show that the leading blanks have disappearedC EMailAddr DSPLY

Once we have made changes to the string object we need to convert it back to an RPG type string again

We do this with the 'getbytes' method

At the end of all this, EMailAddr contains'[email protected]'

The RPG IV equivalent to this process is: EVAL EMailAddr = %Trim(EMailAddr)

Nobody said it was a realistic example !

Invoking Java Methods from RPG

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 11-12

Page 7: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Creating/Manipulating Excel Spreadsheets

Possible courtesy of the Jakarta POI ProjectDetails and downloads at http://jakarta.apache.org/poiWe suggest you download the binary version of the current release

poi-2.5.1-final-20040804.jar

What's a "jar" file?The Java world's equivalent of a zip fileA means of packaging all the required classes for an application

The JVM's CLASSPATH should be set to point to the jar fileThis needs to happen before the JVM is started

DCL VAR(&POI_PATH) TYPE(*CHAR) LEN(1000) + VALUE('/partner400/JavaPOI/JavaPOI/poi-2.5.1-final-20040804.jar') CHGENVVAR ENVVAR(CLASSPATH) VALUE(&POI_PATH) MONMSG MSGID(CPFA981) EXEC(DO) ADDENVVAR ENVVAR(CLASSPATH) VALUE(&POI_PATH) ENDDO

Creating an Excel SpreadsheetBasic sequence is as follows:

Create the Workbook Create the sheet within the workbookBuild a Row within the sheet (**)Build the cells within the rowRepeat from ** until all rows are completedCreate a stream file in the IFS for outputWrite the Workbook to the output fileAnd close the file

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 13-14

Page 8: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Main Line Process

// Create the Workbook workbook = createworkbook();

// Create the sheet within the workbook sheet = createSheet(workbook);

// Now process all records in the file creating a row for each record Read PayrollX; Dow not %eof(PayrollX); Exsr BuildRow; Read PayrollX; Enddo;

// Set up string for filename, and create the stream file for output filename = createString('/Partner400/ExcelTest.xls'); outFile = createFile(filename);

// Write Workbook to output file and close file writeworkbook (workbook: outFile); closefile(outfile);

*inlr = *on;

Examples of the prototypes are shown on the next page

// Create workbookD createworkbook PR O EXTPROC(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFWorkbook' :*CONSTRUCTOR)D CLASS(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFWorkbook')

// Create sheet in specified WorkBookD createSheet PR O EXTPROC(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFWorkbook'D :'createSheet')D CLASS(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFSheet')

// Write the WorkBook to the output fileD writeworkbook PR EXTPROC(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFWorkbook'D :'write')D outputStream O CLASS(*JAVAD :'java.io.OutputStream')

Example Prototypes

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 15-16

Page 9: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

// Build a row for each record in the file Begsr BuildRow;

// Create row and set cell number to zero row = createRow(sheet: rowNumber); cellNumber = 0;

cell = createCell(row: cellNumber); setCellType(cell: stringCell);// Create String Cell Value. string = createString(Badge);// Set cell value. setCellValStr(cell: string); cellNumber += 1;

.........................................

cell = createCell(row: cellNumber); setCellType(cell: numericCell); setCellValD(cell: TaxD);

rowNumber += 1;

Endsr;

Constructing the Rows and CellsNote: Row and Cell numbers start at zero

You will have noticed that some columns were too small

This can be corrected by setting the column widthOne of many formatting options supplied by POINote that the size unit is number of 256ths of a character!Other formatting options include font, heading, color, formulas, and just about anything else you'd ever want to do with a spreadsheet

// Set cell widthD setColumnWidth PR EXTPROC(*JAVAD :'org.apache.poi.hssf.usermodel-D .HSSFSheet'D :'setColumnWidth')D columnNumber 5I 0 valueD ColumnWidth 5I 0 value

........................................

// Set the width of Name column so it fits setColumnWidth(sheet: 2: (%Size(FName) + %Size(LName) + 1) * 256);

Setting Column Width

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 17-18

Page 10: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

The Resulting SpreadsheetThis is what the spreadsheet looks like after setting the width

See Scott Klement's articles for more informationAnd some really good ideas on setting up subprocedures to perform common mult-step tasks

Unlike using simple comma delimited files (CSVs - Comma separated values) using the POI classes allows us to do just about anything with the spreadsheet cells that we could do in Excel itself. Set font type and size, font and background colors, headers, formulas, etc. etc.

One of the less obvious benefits of having the program generate the formulas is that a programmer will get to see them - and hopefully check them! When end users are forced to input their own formulas they can make mistakes. We programmers make mistakes all the time, why expect the users to be perfect? One study undertaken a number of years ago indicated that of all spreadsheets in active use as many as 90% contained errors!

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 19-20

Page 11: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Garbage CollectionNormally the JVM takes care of garbage collection

i.e. It frees up the memory occupied by objects no longer in use

But - it cannot clean up objects created by your RPG codeIt doesn't know about them!

You can free them individually by name using 'freeLocalRef'The example below demonstrates this

But it doesn't work quite as well as you might expect in this situationRemember that while this is RPG code it will behave like Java

How many objects will be reclaimed by the code below?How many were actually created ?

* Instantiate JEMailADDR Using EMailAddr to supply the initial valueC EVAL JEMailAddr = MakeJString(EMailAddr) * Use 'trim' to strip leading and trailing blanks from the StringC EVAL JEMailAddr = TrimJString(JEMailAddr) * Finished with JEMailAddr - free it upC CallP freeLocalRef(env: JEMailAddr)

One of the primary requirements for an OO language like Java is a good garbage collection system. In RPG, this is not an issue as we reuse fields over and over again. Only when we use dynamic memory do we have to concern ourselves at all with this issue. The result is that when we say:

Eval EMailAddr = 'New Content'

All that happens is that the memory locations allocated to EMailAddr have their contents changed to 'New Content'. That's it - end of story.

The story is different in Java. If JEMailAddr is a string object and we perform the equivalent task, the storage is not reused. Instead a new object is created and given the same reference (i.e. name) as the original, an the storage of the new object is what is changed. The original object is then marked as being available for garbage collection. It is only during the garbage collection process that the actual memory will be released for reuse.

The problem is that if RPG creates such a Java object, the normal garbage collection process cannot clean it up, because it has no idea when it would be safe to do so.

That means that unless we want to create a situation where we can literally fill up our memory allocation, we need to handle the situation. Even if memory does not become and issue, performance may well do so.

Note that this is not something you really need to worry about when "playing" with this support. But it should certainly be a concern when using Java objects in production code.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 21-22

Page 12: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Garbage Collection - freeLocalRefIn the example below Four objects are created

freeLocalRef could be used to clean up each set of cell and string immediately we have finished with them

And before the next set is createdBut the resulting code is nasty and repetitious

There is a better solutionUse the ability to identify Object Groups

cell = createCell(row: cellNumber); setCellType(cell: stringCell); string = createString(Dept); setCellValStr(cell: string); cellNumber += 1; freeLocalRef(env: cell); // This has to be duplicated after freeLocalRef(env: string); // we have finished with each set

cell = createCell(row: cellNumber); setCellType(cell: stringCell); string = createString(%TrimR(FName) + ' ' + LName);

Garbage Collection - Freeing Object Groups

beginObjGroupPlaces a "mark" on the the object stack

endObjGroupCauses all objects created since the last "mark" to be released

beginObjGroup(env); // Mark begining of group for cleanup cell = createCell(row: cellNumber); setCellType(cell: stringCell); string = createString(Dept); setCellValStr(cell: string); cellNumber += 1; cell = createCell(row: cellNumber); setCellType(cell: stringCell); string = createString(%TrimR(FName) + ' ' + LName); ....................................... endObjGroup(env); // Clean up all unwanted objects

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 23-24

Page 13: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Last Words on Garbage CollectionBoth methods require a pointer to the JNI environment

The variable "env" passed as the first parameter on the calls

This can be obtained by calling the getJNIEnv APIIt can also "fire up" the JVM and set the Class Path if required

How do you obtain the required procedures?The versions used here are included in the Programmer's GuideA version suitable for cut/paste can be found here:

http://faq.midrange.com/data/cache/282.html Scott Klement includes equivalent procedures in the Service Program published with his articles "How to Excel with RPG and Java"

Search for them at www.iseriesnetwork.comMembership is required

D getJniEnv pr *D inputOpts 65535a varying const options(*nopass)

env = getJNIEnv(); //get JNI environment pointer

When RPG starts the Java Virtual Machine (JVM), there are several options that control how the JVM is started.

You can place these options in the SystemDefaults.properties file. You can use the CLASSPATH environment variable to specify the classpath. You can place these options in an environment variable called QIBM_RPG_JAVA_PROPERTIES.

Any options placed in this environment variable will override the options in the SystemDefaults.properties file.

If you specify the java.class.path option in this environment variable, and you also specified the CLASSPATH environment variable, it is undefined which value will take precedence for the classpath. 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 and 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

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 25-26

Page 14: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

RPG Subprocedures as Java methods

Calling the method from Java

Enabling routines for use from Java & RPG!

Writing Java "Methods" in RPG

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 27-28

Page 15: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Coding RPGIV Native Methods

H NoMain Thread(*Serialize)

FProduct1 IF E K Disk FCATEGOR1 IF E K Disk

* Prototype for the new RPG "method" getDescription D getDescription PR 50A EXTPROC(*JAVA:'ProductClass'D :'getDescription')D prodCode 7A CONST

* Proc. interface for getDescription - just a regular RPGIV subproc!P getDescription B ExportD PI 50AD prodCode 7A CONST

* Definitions for local working variables D ProductDesc S 50A Varying

The prototype should look familiarIt is similar to the prototype for a conventional subprocedureThe exception is the Java information in the EXTPROC keyword

The class name ProductClass ties the method to the parent class Note use of Thread(*Serialize) for safe Java/RPG inter-operability

As you can see, when defining a Java Native Method we use the same form of the EXTPROC keyword that we use when invoking Java methods. That is the only real difference that we have to code for.

Under the hood, there is a lot more going on. For example it is necessary to transform the RPG character string into a Java byte string. Don't worry though - this is all taken care of by the compiler.

Our subprocedure, together with any others that we wish to use as Native Methods, must be bound into a Service Program. This Service Program will be loaded by the Java code. From then on, the RPG code is used just like any other method. Well almost .... there is one small syntax difference which we will see when we look at the Java code.

It is beyond the scope of these notes to get into the details of why Thread(*Serialize) is needed for safe Java/RPG inter-operability, but you can either just take our word on it, or read up on the subject and then take our word on it <grin>. Either way you should understand the full implications of Java/RPG inter-operability before committing applications to production.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 29-30

Page 16: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

C ProdCode Chain Product1

C If %Found(Product1)C Eval ProductDesc = %Trim(ProdDs)C CatCod Chain Categor1

C If %Found(Categor1)C Eval ProductDesc = ProductDescC + '(' + %Trim(CatDes) + ')'C ElseC Eval ProductDesc = ProductDesc + '(Category 'C + CatCod + ' Not found)'C EndIfC ElseC Eval ProductDesc = 'Product ' + ProdCodeC + ' Not found'C EndIf

C Return ProductDesc P getDescription E

Coding RPGIV Native Methods This page shows the actual subprocedure logic for our example

Just regular old RPG - nothing specialIt simply builds a composite product description

As can be seen from this example, the RPG logic comprising our new Java Native method is no different than it would be if we were writing it to be called from RPG. The differences (as you saw on the previous chart) are in the prototype and procedure interface.

If it were essential to pass back to the Java program a Java object (for example a String class object) we could do so by invoking the required methods and returning the object. It is probably better however to simply pass back an RPG data type (as we do in this example) and have the Java program perform whatever typecasts may be necessary.

Because of this "undercover" work, we cannot call a Native method directly from RPG. If we want to have the same subprocedures available to our regular RPG code we should code them in the normal way and then provide a second subprocedure that will "wrap" them as Native methods. We will show you what we mean on a later chart.

Note that our example is really incomplete since every NOMAIN procedure that uses files should provide a method of explicitly closing them (the compiler will warn about this). Obviously that subprocedure should also be surfaced as a Java Native Method to allow the Java program to properly close the files.

The following charts describe the basic elements that need to be coded in the Java application in order to us our Native Method.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 31-32

Page 17: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

public class ProductClass {

// Prototype for Native RPG method

native byte[] getDescription (byte productCode[]); static{ try {

System.loadLibrary("TESTRPGJNI"); // Load Native Method SRVPGM } catch (UnsatisfiedLinkError e1){

// Cannot find the service program. Write error message & exitSystem.out.println("I did not find TESTRPGJNI *SRVPGM.");System.exit(1);

}}

Declaring the Native Method Before using the method the Java class must:

Specify a prototype for the method - Note the native keywordLoad the required Service Program

System.loadLibrary takes care of this

Invoking the Native Method

public void displayOrderInfo() {

byte result[];

// invoke the RPGIV method

result = getDescription(str.getBytes());

// Print out the result

System.out.println("The description of product number " + str + " is:");

System.out.println(result.toString());}

The method is invoked just like any otherThe fact that it is coded in RPG makes no difference at this point

A great opportunity for collaborationThe RPG programmers write the business logic that accesses the OS/400 database and processes the business rulesThe Java programmers write the User Interface

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 33-34

Page 18: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

"Sharing" Subprocedures with Java

H NoMain Thread(*Serialize)

FProduct1 IF E K Disk FCATEGOR1 IF E K Disk

* Prototype for the new RPG procedure getDescr D getDescr PR 50A D prodCode 7A CONST

* Procedure interface for getDescrP getDescr B ExportD PI 50AD prodCode 7A CONST

* Definitions for local working variables D ProductDesc S 50A Varying

Java and RPG cannot both call the same subprocedureThe call interface for JNI is very different from the normal RPG

The subprocedure must be converted to be called from RPGThat means just removing the ExtProc(*Java ........ keywordWe've also changed the name of the subprocedure

"Sharing" Subprocedures with Java

RPG Batch or

InteractiveProgram

No need to maintain two versions of the subprocedureWe can still share a single version between Java and RPG

The best way to share the code is define a proxy or wrapperIt is this version that is called from JavaIt does nothing but call the RPG version

RPGService Routine

JavaProgram

RPGProxy

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 35-36

Page 19: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Java will call this Proxy version

H NoMain Thread(*Serialize) * This prototype should be /COPY'd in D getDescr PR 50A D prodCode 7A CONST

* Prototype for the new JNI "method" getDescription D getDescription PR 50A EXTPROC(*JAVA:'ProductClass'D :'getDescription')D prodCode 7A CONST

* Proc. interface for getDescription - just a regular RPGIV subproc!P getDescription B ExportD PI 50AD prodCode 7A CONST

C Return getDescr(prodCode)

P getDescription E

As you can see there is not a lot to itBoth subprocs can (& probably should) be in the same source member

This routine does nothing but call the RPG version

Writing RPG Native methods and invoking them from JavaThere are no major problems here

Although you need to be aware of the issues when multithreaded Java applications are in use

Creating and manipulating Java objects from RPGThere are traps for the unwary

The Java garbage collection needs your help to "clean up" your old objectsObjects that you want to persist between calls must be registered with the JNI interface

Check the manual for further detailsYou will find them in the Programmers Guide

Under the heading "RPG and Java" in "RPG and the eBusiness World"

Have fun with this - there's a whole new world out there! E-mail me if you would like the full sources for the examples shown in this presentation

Summary

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 37-38

Page 20: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Geert Van Landeghem's web site (www.foundation.be)Tutorial on generating basic Excel filesNEW Free tool to generate RPG Prototypes from any Java jar or zip!

WDSC has similar support but see the Notes page for details

Bob Cancilla's IGNITe/400 Article on using Javamail from RPGwww.ignite400.org/news/news2002070401.htm

David Morris' - Sending E-Mail from RPG www.itjungle.com/fhg/fhg051204-story04.htmlAlso Sending E-Mail from RPG, Take Two

www.itjungle.com/fhg/fhg102704-story01.html

Scott Klement's Programming Tips Newsletter In particular the "How to Excel with RPG and Java" series

Search for it at www.iseriesnetwork.com (Membership required)

Aaron Bartell's Javamail and XML Parsing exampleswww.mowyourlawn.com

Other RPG / Java References

The Java prototyping support from Geert's new tool and that provided within WDSC at first glance look similar but are really quite different.

IBM's WDSC tool generates a lot more code, generating as it does the object definitions and method call in addition to the prototype itself. At first glance this seems very useful but ... The biggest problem is that it will only generate for one method at a time. The result is that the process is very slow and protracted and really only useful when generating for a single method. That is not something you'll want to do very often.

Geert's tool while not generating as much of the overall code, does at least let you select multiple methods at a time and will generate prototypes for all of them. On the whole we find this more useful than the WDSC option.

Hopefully IBM will study what Geert has done and update the WDSC tool to make it a little more useful in production work.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 39-40

Page 21: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Questions?

Following charts are FYI

We will not discuss them during the session

Comparing Java Objects Java Objects can be tested for equality

But what constitutes equality ????

D JString1 S O CLASS(*JAVA:'java.lang.String') D JString2 S O CLASS(*JAVA:'java.lang.String')

D MakeJString PR O EXTPROC(*JAVA:'java.lang.String': D *CONSTRUCTOR) D InputString 256A Options(*VarSize)

D StringData S 20A Inz('Test String')

/Free JString1 = MakeJstring(StringData); JString2 = MakeJstring(StringData);

If JString1 = JString2; Dsply 'Test 1: They are the same'; EndIf;

JString1 = JString2;

If JString1 = JString2; Dsply 'Test 2: They are the same'; EndIf;

What do you expect this

program to display?

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 41-42

Page 22: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Note that arrays of objects are allowed, but fields of type 'O' cannot be subfields of a Data Structure

It is important to understand that fields of type 'O' are NOT pointers, although they do store references to objects. Unlike a regular RPGIV field the object does not really exist simply because you have coded its definition in your program. The definition is simply a template. You must "instantiate" the object using its class constructor before you can reference it. Those of you familiar with Java will recognize this behavior but it may not be obvious to those who have not been exposed to the Java language. Think of the definition of the object as being like the DDS definition of a record - compiling the DDS does not place a record in the file, you must "instantiate" the record by writing it to the file.

Currently the first parameter must be specified as *Java, but now (V5R1) that the C++ compiler is available to all AS/400 and iSeries application developers we may see greater C++ usage and the compiler may eventually be updated to allow interfacing to C++.

Note that the method name must be fully qualified and that the special method name of *CONSTRUCTOR is used to create a new instance.

Even if you never intend to write a line of Java, there may be others in your shop who will. Writing Native Methods for them in RPGIV can provide them with some very powerful extensions to their Java toolkit and allow for significant code reuse. Why write it from scratch in Java using JDBC etc. when you can use your high-speed RPG code!

Java Data Type RPG IV Equivalent RPG IV Definitionboolean Indicator N

byte Integer 3I 0Character 1A

byte[ ] Char field length > 1 nA {Varying}Array of Char with length = 1 1A Dim(x)

Date, Time, Timestamp D, T, Zshort Integer 5I 0char UCS-2 length=1 1C

char[ ] UCS-2 length>1 nC {Varying}UCS-2 length 1 1C Dim(x)

int 4-byte integer 10I 0long 8-byte integer 20I 0float 4-byte float 4F

double 8-byte float 8FAny object object O Class(........)Any array Array of equivalent type Dim(x)

Java and RPG Data Type Equivalents

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 43-44

Page 23: Brewing Mixed Java and RPG ApplicationsYour Partner in AS/400 and iSeries Education Brewing Mixed Java and RPG Applications Jon Paris Jon.Paris @ Partner400.com Yet More Things You

Notice that for some Java data types, there are multiple RPG equivalents. In some cases the choice you make will have an impact on the data itself.

For example, when a Java byte type is mapped to character, ASCII conversion occurs. However, when it is mapped to integer there is no conversion.

For arrays of any type in Java, you can declare an array of the equivalent type in RPG. However, note that you cannot only use and element length of 1 (i.e. 1A or 1C)

For RPG array data types, OPTIONS(*VARSIZE) should normally be coded for array parameters, since Java arrays cannot be declared with a fixed length.

You may have noticed that Zoned, Packed, Binary, and Unsigned data types are not listed for Java. That's because they don't exist in the language. If you pass these fields, the compiler will do the appropriate conversion, but it may result in truncation and/or loss of precision.

When you prototype a Java method that takes Boolean, byte, int, short, long, float, or double parameters - you must specify the VALUE keyword.

Objects can only be passed by reference, you cannot specify the VALUE keyword with type O. Strange as it may seem to an RPGer, since arrays are seen by Java as objects, they must also be passed by reference. This includes both character and byte arrays.

© Copyright Partner400, 2006 Brewing Mixed Java and RPG Applications - Page: 45-46