This chapter provides an overview of Java class and discusses the following topics:
Supported versions of Java.
Naming standards for classes and packages.
System setup for Java classes.
From PeopleCode to Java.
From Java to PeopleCode.
PeopleCode and Java data types mapping.
Considerations when using the PeopleCode Java functions.
Error handling and the PeopleCode Java functions.
The Java debugging environment.
Java object declaration.
Scope of a Java object.
PeopleCode Java built-in functions.
Using the PeopleCode Java functions, you can access Java classes, or create instances of Java objects. Calling a Java program from PeopleCode can greatly extend your application. Also, the PeopleCode integration with Java enables you to pass parameters such as record, record fields, or rowsets into Java programs.
The PeopleCode Java functions are:
CopyToJavaArray
CopyFromJavaArray
CreateJavaArray
CreateJavaObject
GetJavaClass
See Also
http://java.sun.com/index.html
PeopleSoft supports Java version 1.4.1 for all its platforms. The Java Runtime Engine (JRE) comes bundled with PeopleSoft for all but the z/OS platform. On that platform, you may have to install the JRE.
See your platform installation documentation for more information.
PeopleSoft recommends following Sun standards for naming classes and packages.
Java classes delivered with PeopleSoft are generally in the following directory for Windows machines:
<PS_HOME>/appserv/classes
Java classes delivered with PeopleSoft are generally in the following directory for Unix machines:
<PS_HOME>\classes
At PeopleSoft, we use the following for the package hierarchy:
com.peoplesoft.<prodline>.<prodcode>
Where prodline is the company standardized product line code (like hrms) and prodcode is the product code unique within the product line (like hr).
In addition, if there are any classes that are common across products, they are placed into the common package for that product line, that is:
com.peoplesoft.<prodline>.common
See Also
http://java.sun.com/docs/codeconv/index.html
If you only access the classes that come defined with PeopleSoft you don't need to do any additional setup.
If you include your JAR or class files in the Java directory you don't need to do any additional setup. That is, you don't need to do anything if your files are in the following directory:
<PS_HOME>\appserv\classes
If you create your own Java classes that you want to access with PeopleCode, and you do not store them in the Java directory, you must create a PS_CLASSPATH environment variable that points to where your classes are stored. The exact path depends on how and where you package your classes.
If you package your Java classes in a JAR file, and you do not place your JAR file in the Java class directory, you must specify the JAR file name (with the JAR extension) in the PS_CLASSPATH environment variable.
Usually when there is a package hierarchy, the JAR file is at the package root, and contained within it a directory-like structure of the class files. For example, if the package hierarchy is like this:
c:\myjava\com\mycompany\myprod\xxx.java
Then you would have to set your PS_CLASSPATH environment variable to the following:
c:\myjava\com.mycompany.myprod.jar
Note. PeopleSoft recommends using the utility that comes with the Java SDK for creating JAR files.
If you don't store the Java classes you create in a JAR file, and you do not place your class files in the Java directory, the PS_CLASSPATH environment variable must point to the top level of your package hierarchy.
For example, suppose your Java classes were in the following package:
c:\myjava\com\mycompany\myproduct\
You would set the PS_CLASSPATH environment variable to:
c:\myjava
Like most environment variables, you can specify more than one entry. On Windows, the PS_CLASSPATH entries are separated by semicolons. On Unix, they're separated by colons. The following is for Windows:
c:\myjava;d:\myjava\com\mycompany\myproduct\myjar.jar; . . .
The following would be for Unix:
/etc/myjava:/home/me/myjava/com/mycompany/myproduct/myjar.jar: . . .
This PS_CLASSPATH setting must be set for the process that runs the Java. For example, if Java is being called from PeopleCode that is running on the Application Server, it is the Application Server process that needs this setting. Similarly, if the Java is being run from PeopleCode in the Application Engine, that run of the Application Engine must have this setting.
Also when developing your own classes you must be aware that most Java virtual machines cache the class definitions. This means that even if you change the class files, a running Java virtual machine (inside, perhaps, an Application Server) that has loaded and is running the old version of the class files. It won't pick up the new version of the class files. You must restart the Application Server to make it reload the new classes.
See your system documentation for more information about setting up an environment variable.
In this section, we provide an overview of state management concerns and present the following examples:
State Management Concerns.
CreateJavaObject example.
CreateJavaArray example.
GetJavaClass example.
The application server is stateless, which means that it doesn’t keep any information (state) for its clients between calls to it. For one reason, calls to the application server can use different actual servers for different calls. When you are using Java in the application server, be careful to not leave state in the Java virtual machine that would cause your application to fail if a different application server (which would use a different invocation of the Java virtual machine) was used for subsequent calls. One method to leave state in the virtual machine is to use static (class) variables.
Similar considerations to these apply using Java in Application Engine programs, though here the difficulty arises when you try to checkpoint and then restart the program. The restart starts with a Java virtual machine invocation that doesn’t have any of the state you might have stored into the Java virtual machine before the checkpoint.
JavaObject variables cannot have Global or Component scope because of this lack of ability to save the state of these objects.
An example of this is issuing messages. When you're running with PeopleSoft Pure Internet Architecture and issue a message, the message is produced by an end-user action, so the Application Server gathers up its state to return it to the browser. This state saving attempts to save the current PeopleCode execution state, causing it to issue an error because of the JavaObject.
The solution is to not have any non-Null JavaObject objects when the message is issued.
The following is a simple Java program:
public class PC_Java_Test{ public String pcTest(){ String message; message = "PeopleCode is successfully executing Java."; return message; } }
Here is the PeopleCode that calls this Java program. Note that the JavaObject is set to NULL before the message is issued.
&java_test = CreateJavaObject("PC_Java_Test"); &java_message = &java_test.pcTest(); &java_test = Null; WinMessage(&java_message);
In SavePreChange, Workflow, or SavePostChange PeopleCode the situation is more complicated. Usually messages with a zero style parameter (no buttons other than OK and perhaps Explain, therefore no result possible except OK) are queued up by the Application Server. They are output by the browser when the service completes, so the serialization won't happen until after the PeopleCode has finished, so you won't have to set your JavaObject to NULL. With other kinds of messages, you must do this.
The following is an example program creating a Java object from a sample program that generates a random password.
/* Example to return Random Passwords from a Java class */ Local JavaObject &oGpw; /* Create an instance of the object */ &oGpw = CreateJavaObject("com.PeopleSoft.Random.Gpw_Demo"); &Q = "1"; /* Call the method within the class */ &NEW_VALUE = &oGpw.getNewPassword(&Q, PSRNDMPSWD.LENGTH); /* This is just returning one value for now */ PSRNDMPSWD.PSWD = &NEW_VALUE;
Suppose we had a PeopleCode array of strings (&Parms) that we wanted to pass to a Java method xyz of class Abc. This example assumes that you don't know when you write the code just how many parameters you will have.
Local JavaObject &Abc, &RefArray; Local array of String &Parms; &Parms = CreateArray(); /* Populate array how ever you want to populate it */ &Abc = GetJavaObject("com.peoplesoft.def.Abc"); /* Create the java array object. */ &JavaParms = CreateJavaArray("java.lang.String[]", &Parms.Len); /* Populate the java array from the PeopleCode array. */ &RefArray = GetJavaClass("java.lang.reflect.Array"); For &I = 1 to &Parms.Len &RefArray.set(&JavaParms, &I - 1, &Parms[&I]); End-For; /* Call the method. */ &Abc.xyz(&JavaParms);
The following example gets a system class.
&Sys = GetJavaClass("java.lang.System"); &Sys.setProperty("java.security.policy", "C:\java\policy"); WinMessage("The security property is: " | &Sys.getProperty("java.security.policy")); &Props = &Sys.getProperties(); &Props.put("java.security.policy", "C:\java\policy"); &Sys.setProperties(&Props); WinMessage("The security property is: " | &Sys.getProperty("java.security.policy"));
The Java classes delivered with PeopleTools enable you to call PeopleCode from your Java program. Calling into PeopleCode works only from Java code that you have initially called from PeopleCode.
You must call PeopleCode facilities only from the same thread that was used for the call into Java. PeopleTools is not multithreaded.
You cannot call any PeopleCode facility that would cause the server to return to the browser for an end-user action, because the state of the Java computation cannot be saved and restored when the action is complete.
See Also
Considerations When Using the PeopleCode Java Functions
Use the SysVar Java Class to refer to System Variables, such as %Language or %DBType.
For example, %Session, becomes SysVar.Session()
See Also
Use the SysCon Java Class to refer to system constants, such as %SQLStatus_OK or %FilePath_Absolute.
For example, %CharType_Matched becomes SysCon.CharType_Matched.
Use the Func Java Class to refer to built-in functions, such as CreateRowset or GetFile.
For example, SetLanguage(LANG_CD) becomes Func.SetLanguage(LANG_CD)
The Name Java Class enables you to use the PeopleSoft reserved item references. This enables you to reference pages, components, records, fieldnames, and so on.
For example, in PeopleCode you can refer to a record field using the following:
recname.fieldname
With the Name class, you can use a similar construct:
new PeopleSoft.PeopleCode.Name("RECNAME", "FIELDNAME");
Note that these must be in the exact case as the item. As all PeopleTools items are named in uppercase, that means you must use uppercase.
As another example, in PeopleCode you can refer to a page using the following:
PAGE.pagename
In Java, it would be:
new PeopleSoft.PeopleCode.Name("PAGE", "PAGENAME");
The existing PeopleCode classes (like Array, Rowset, and so on) have properties and methods you can access.
PeopleCode classes have the same names, so Record becomes Record, SQL becomes SQL, and so on.
Methods are accessed by the method name.
The name of a property is pre-pended with either get or set, depending on whether you're reading or writing to the property.
For example, to get the IsChanged property would be getIsChanged. To set the value for a field would be &MyField.setValue.
Here is an example of a Java program that uses PeopleCode objects to access the database:
/* * Class Test * * This code is used to test the Java/PeopleCode interface. * */ import PeopleSoft.PeopleCode.*; public class Test { /* * Test * * Add up and return the length of all the * item labels on the UTILITIES menu, * found two different ways. * */ public static int Test() { /* Get a Rowset to hold all the menu item records. */ Rowset rs = Func.CreateRowset(new Name("RECORD", "PSMENUITEM"), new Object[]{}); String menuName = "UTILITIES"; int nRecs = rs.Fill(new Object[]{"WHERE FILL.MENUNAME = :1", menuName}); int i; int nFillChars = 0; for (i = 1; i <= rs.getActiveRowCount(); i++) { String itemLabel = (String)rs.GetRow(i) .GetRecord(new Name("RECORD", "PSMENUITEM")) .GetField(new Name("FIELD", "ITEMLABEL")) .getValue(); nFillChars += itemLabel.length(); } /* Do this a different way - use the SQL object to read each menu item record. */ int nSQLChars = 0; Record menuRec = Func.CreateRecord(new Name("RECORD", "PSMENUITEM")); SQL menuSQL = Func.CreateSQL("%SelectAll(:1) WHERE MENUNAME = :2", new Object[]{menuRec, menuName}); while (menuSQL.Fetch(new Object[]{menuRec})) { String itemLabel = (String)menuRec .GetField(new Name("FIELD", "ITEMLABEL")) .getValue(); nSQLChars += itemLabel.length(); } return nFillChars + 100000 * nSQLChars; } } This can be run from PeopleCode like this: Local JavaObject &Test; Local number &chars; &Test = GetJavaClass("Test"); &chars = &Test.Test(); &Test = Null; WinMessage("The character counts found are: " | &chars, 0);
You call a Java program from an Application Class the same way you do using any other PeopleCode program, that is, by using one of the existing Java class built-in functions.
Calling an Application Class from a Java program has the following considerations:
Application Classes must be accessed using the object built-in functions, such as CreateObject, ObjectDoMethod, ObjectGetProperty, and so on.
You cannot declare a variable of type HR.Package.SomeClass in your Java program. The variable must be of type Object.
There is no pre-pending the word ‘get’ or ‘set’ for properties. All classes, methods, and properties are passed as strings.
The following is an example of how to call an Application Class from a Java program.
This is the Java program:
package com.peoplesoft.pcode; import PeopleSoft.PeopleCode.*; public class foo { public foo() { } public String getString() { Object foo = Func.CreateObject("GTP:Foo", new Object[]{}); return (String)Func.ObjectDoMethod((Peer)foo, "GetString", new Object[]{}); } }
The following is the Application Class Foo, in the Application Package Foo:
class Foo method GetString() Returns string; end-class; method GetString /+ Returns String +/ Return "Hello"; end-method;
The following is the PeopleCode program that starts it all:
Local JavaObject &foo = CreateJavaObject("com.peoplesoft.pcode.foo"); GTP_PARSER.GTP_STR_RESULT = &foo.getString();
The following table describes the matching of types for resolution of overloaded Java methods and basic conversions. The first Java Type/Class is the one that is produced in the absence of any other type of information.
PeopleCode Type |
Java Type/Class |
Float |
double, float |
Number |
double, float, byte, char, short, int, long |
Integer |
int, byte, char, short, long |
Boolean |
Boolean |
String |
java.lang.String |
Date |
java.sql.Date |
Time |
java.sql.Time |
Date Time |
java.util.Date |
any kind of object |
any kind of object |
The following table represents the conversions done to produce the Java class java.lang.Object. In addition to these, the conversions (listed in the previous table) from String onwards are done to produce a java.lang.Object.
PeopleCode Type |
Java Type/Class |
Float, Number |
java.lang.Double |
Integer |
java.lang.Integer |
Boolean |
java.lang.Boolean |
The following table represents other conversions that are done as required by the signature of a Java method or constructor.
PeopleCode Type |
Java Class |
Integer, Number, Float |
java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Long, java.lang.Float, PeopleSoft.PeopleCode.intHolder, PeopleSoft.PeopleCode.doubleHolder |
String |
PeopleSoft.PeopleCode.StringHolder |
peoplecode builtin class Xxx |
PeopleSoft.PeopleCode.Xxx |
JavaObject |
corresponding Java object |
Some PeopleCode built-in functions can't be called from a Java program. Many of these restrictions arise because you can't serialize Java objects. Inside Java, you can't serialize and save the state of the Java Virtual Machine (JVM.)
This means that you cannot call the following built-in functions:
Think-time functions, such as DoCancel, Prompt, RevalidatePassword, and so on.
Math functions, such as Abs, Cos, and Sin. Use the Java math functions instead.
Java class functions, such as CreateJavaArray, CreateJavaObject, or GetJavaClass.
Deprecated functions, such as SetNextPanel, PanelGroupChanged, and so on. Use the new function instead, like SetNextPage, ComponentChanged, and so on.
PeopleCode language elements, such as Exit, Return, If, and so on.
Cursor position, such as SetCursorPos.
Functions that rely on specific character encoding, such as char, code, exact, codeb, and so on.
Menu appearance functions, such as CheckMenuItem, HideMenuItem, and so on.
Transfer functions such as Transfer or TransferPage.
DoSaveNow isn't allowed. However, DoSave is.
When you're creating your Java program, keep the following points in mind:
If you're starting from an online application, avoid calling anything that will wait a long time.
If you use third-party Java that require third-party platforms, you are limiting your program to just those platforms.
When setting a null date in Java, use the following:
myField.SetValue("");
See Also
When PeopleCode is called from your Java program it executes what are called native methods. These methods looks like regular Java methods in their definition but are implemented in the PeopleTools layer. In order to go from Java into PeopleTools you have to use an interface called the Java Native Interface (JNI). There is a cost associated with each transition across the JNI. Using the CopyToJavaArray and the CopyFromJavaArray functions may improve your performance, as they act as a type of bulk data copy that minimizes the transition overhead.
For example you could copy an array by copying each element using the array's Get method. However, that would require traversing the JNI twice for each element; once going into Tools and once coming back from Tools. Not only is there transition overhead but there is also conversion between object types. For example a PeopleCode string has to be converted to a Java String and vice-versa. While these two builtins do not eliminate the latter conversions, they minimize the number of transitions across the JNI.
These functions can be used when you are selecting data into a PeopleCode array and you want to copy that data into a Java array.
These functions also allow you to supply an optional parameter that specifies the list of items you want copied.
See Also
Memory is managed in the JRE by the Java garbage collector. Because PeopleTools has no control over when the Java garbage collector runs (apart from a user in their Java program calling it using system.gc()), PeopleTools interacts dynamically with the Java runtime garbage collector. In particular, PeopleCode objects created from a Java program (such as records, fields, and so on,) are in effect peer objects of real PeopleCode objects in PeopleTools. The release of these objects must be linked. Using the weak reference mechanism in Java, PeopleTools dynamically interracts with the Java garbage collector each time the execution thread passes through the Java Native Interface(JNI.) This allows long-running Java applications in a PeopleTools context to function without having to wait for an "end of service" event for object cleanup.
There might be occasions where a Java application creates many application classes and wants to force the PeopleTools garbage collector to run. That can be achieved by calling the CollectGarbage function. This is not normally necessary.
See Also
Java functions throw exceptions to indicate something unusual has happened. However, all exceptions from Java called by PeopleCode are turned into fatal errors. You can catch these exception by enclosing the call to Java in a Try-Catch PeopleCode block. If you do not try to catch these exception, the PeopleCode program is terminated, and the user transaction must be canceled.
PeopleSoft recommends that you write a Java wrapper to handle errors.
Use either the All or None built-in functions to check values that are returned if you think you may call a Java method that is defined to return a string, but returns a Null object reference instead. Java Null object references are automatically converted into PeopleCode Null object references.
Accessing the Application Log File
For doing additional error handling in your application, you can access the application log file using the PeopleCode WriteToLog built-in function. For example:
Func.WriteToLog(SysCon.ApplicationLogFence_Level1, myLogString);
See WriteToLog.
To use Sun's JPDA V1.0 debugging architecture, you must do the following. These instructions are general: how you actually set up the debugger depends on your system.
To use the Java Debugging Environment (JDB):
Download and install a copy of JPDA V1.0.
Set the path for your system.
Suppose you install JPDA V1.0 in C:\jpda. Set your PATH environment variable to include C:\jpda\bin.
Set the path for the application server.
For the application server, set the Domain Settings/Add to PATH to include C:\jpda\bin.
Set the JavaVM Options.
Set the JavaVM Options to be something like the following (see the JPDA documentation for a more complete example):
-Xdebug -Djava.compiler=NONE -Xnoagent -Xrunjdwp:transport=dt_socket,suspend=n,address=8765,server=y
Run the debugger.
After starting the tools session and causing it to start the JVM, you can use the JDB command line debugger that comes with JPDA, using a command like the following:
jdb -connect com.sun.jdi.SocketAttach:port=8765
You can also use the (no cost) Forte for Java Community Edition IDE from Sun or any of the Java IDEs noted on the JPDA pages.
See Also
http://java.sun.com/products/jpda
http://www.sun.com/forte/ffj/ce/index.html
You should declare a Java object as type JavaObject. For example:
Local JavaObject &MyJavaClass;
Note. Java objects can be declared as type Local only.
A Java object can be instantiated from PeopleCode only. This object can be used anywhere you have PeopleCode, that is, in message subscription PeopleCode, Component Interface PeopleCode, record field PeopleCode, and so on.