Performancing Metrics

Vamsi Tokala's blog: White Paper - Java RMI Communication with LoadRunner

Saturday, April 23, 2011

White Paper - Java RMI Communication with LoadRunner

Java RMI

Java RMI Communication with LoadRunner

       Vamsidhar Tokala


This paper provides tips and tricks for HP LoadRunner JAVA RMI configuration, scripting, and execution. This guide is intended to help testers to understand the concepts of Java RMI and to use HP LoadRunner for Java RMI Scripting using Java Record and Replay protocol.

Introduction


LoadRunner is one of the very few tools available in the market which supports Java RMI protocol.  Information and the expertise available in the public domain is very limited for this protocol and developing test scripts for applications that use RMI involves Java programming, and requires understanding of the Java classes involved in client/server communications.  This article will enable testers with a solid background to address the challenges ahead.

Java RMI


JAVA RMI is distributed object protocol for communication between distributed objects.  It provides infrastructure services such as error, exceptional handling, parameter passing and security context. Client stubs and server skeletons are generated automatically and act as an interface between the application and the rest of the RMI system.

When a client invokes a call to a business object, it needs to get a remote object reference (Stub) to the remote object (skeleton), which intercepts the call and invokes the corresponding method. Remote objects works with container to execute resource management strategies such as instance pooling and provide support for transaction persistence and security

The way client gets a remote reference to an object is by first looking up home interface of the object via JNDI(Java Naming And Directory Interface) and then invoke create method defined in the home interface. If the object client wants to call already exists, then client can invoke one of the find methods defined in the home interface after the JNDI lookup. Server typically provides a naming server for the clients to look up objects deployed on it.

When a client invokes a method call of an object of an application deployed in the server, client actually invokes a corresponding method call on a local proxy (Stub) of the object deployed in server. Local proxy serializes the parameters of the call and sends them to server side proxy (Skeleton). Skeleton collaborates with the container to provide middle ware services such as concurrency control, connection pooling. Once the call is processed, results will be returned to Skeleton, stub and then to client eventually.

RMI Communication with LoadRunner


LoadRunner will act as a client stub during RMI communication with the server. It acts like a proxy of the object on the server side. It sends the method call to the Skeleton, which is present on the server side.

When remote calls from separate clients are placed (executing in different JVMs) each call will run in a separate thread. However, if you make concurrent calls from the same client then calls will execute on the same server thread.

Configure LoadRunner’s Java RMI recorder


In order to allow LoadRunner to capture RMI communication with the application ensure the following is done

1.        Install JDK. JRE alone is not sufficient for LoadRunner to record the RMI communication
2.        Identify the jar files required for the application to run.  Do the following steps to determine the same
·         Manually access the application through browser/batch file.
·         Go to Control Panel – java – Temporary internet files – Settings - Select View applications - Show JNLP Descriptor

3.        Download all the jar files listed in the jnlp file to a local folder from the application server (Refer JNLP section to look at a sample file). Alternatively look in the Java console for all JARs downloaded to the cache, and copy these to a local directory.(When an application lunches from the browser a copy of all the jar will get downloaded to a temporary directory in local machine.)

4.        Get all the application properties and parameters in JNLP file (see below for a sample format)

5.        Create the Java security policy file - d:\all.policy - with contents:

grant {
permission java.security.AllPermission;
};

The java.security.AllPermission is a permission that implies all other permissions. Granting AllPermission should be done with extreme care. Thus, it grants code the ability to run with security disabled. Extreme caution should be taken before granting such permission to code. This permission should be used only during testing.

6.        Configure class path   in the environment variables for all the jar files in the local folder plus
\bin
classes
\classes\srv
\jre\lib\rt.jar

b) Set %PATH% to point to the JDK and verify this with java -version

7.        Create a batch file with the information available from JNLP file as shown below

-Djava.security.policy=d:\all.policy
-DUSE_JAAS="false" -Dclient_master.properties="/retek/client_master.properties"
-Xms256M -Xmx256M
-Djava.naming.provider.url="opmn:ormi://XXX:6007:XXX-rpm/rpm12"
-DNAMING_URL="opmn:ormi://XXX:6007:XXX-rpm/rpm12"
-Djava.naming.factory.initial="oracle.j2ee.rmi.RMIInitialContextFactory"
-DNAMING_FACTORY="oracle.j2ee.rmi.RMIInitialContextFactory"
com.retek.rpm.gui.security.RpmUIClient

8.        Run the batch file in the local machine. It should invoke the application with out any issues.  In case of any issues while lunching the application using batch file, relook at all the steps from 1 to 8.

9.        LoadRunner has predefined hooks for Java RMI called rmi.hooks which is present Dat folder of LoadRunner installation directory.  The LoadRunner recorder uses these hooks to capture all Java classes as they are loaded into the Java Virtual Machine (JVM). When ever a hooks method is called, the same will be recorded into LoadRunner Script.  
To enable hooks, just remove ‘;’ character present is rmi.hooks file located at \dat & \classes directories.

Customized hooks for any classes or methods specific to the application can also be created with a filename called user.hooks and place it under LoadRunner/classes directory. 

10.     Under LoadRunner recording options: Configure the class path as in step 6 and add each of the jar files in the same order as in JNLP file (which is very important) in LoadRunner recording options.

11.     Compile and run the empty Java script with out errors.

12.     Record the application either with the java application by specifying the application parameters defined in the batch file or by selection the application type as batch file. LoadRunner launches the application and captures the methods and classes defined in the hooks file.

Script Parameterization

1.        Typical LoadRunner functions like vuser_init(); vuser_end() will not have any impact in the script. So after the script is recorded move the login part of the application code to init () function and logout to end () and the rest in action () function of the script.

·         init() method will be called once in the beginning of the run
·         action() method will be called once per each iteration
·         end() method will be called once at the end of the run
2.        Parameters defined in the script should assign to  java objects  as shown below for different data types
·         String promotionEventDescription = "";
·         com.retek.platform.util.type.RDate promotionEventStartDate =     new com.retek.platform.util.type.RDate ("", "MM/dd/yyyy"); //application specific date object
·         long departmentId = Long.parseLong("");//long
·         String departmentDisplayId = ""; //string

Serialization and De serialization

During the recording process LoadRunner automatically serializes the objects. Serialized objects are flattened into bytes and subsequently inflated in the future.  LoadRunner saves the objects into binary files with sequentially numbered and saved under LoadRunner Vuser directory. First file will be named as 1 and the second file as 2 and so on...

These classes captured in the script are serialized and deserialized during replay.  The below example code is generated by VuGen

 _object_array83 = new java.lang.Object[] {_clientcontext1, _tslcascadesearchcriteriaimpl1};  // IDLSequence
_string22 = "com.retek.rpm.app.item.service.TslCascadeSearchCriteriaImpl __CURRENT_OBJECT = {" +
  "}";
 _class10 = (java.lang.Class)lr.deserialize(_string22,21);  // RMIComponent
 _class_array27 = new java.lang.Class[] {_class1, _class10};  // IDLSequence
_object27 = _rpmcommandexecutionserviceremote27.executeCommand("com.retek.rpm.app.item.service.TslCascadeAppService", "findItems", (java.lang.Object[])_object_array83, (java.lang.Class[])_class_array27);

)

Forms of deserialization

There are two forms of deserialization used in LoadRunner.
lr.deserialize (int, boolean)
First form uses the int argument and it takes the Sequence number of the serialized object of the file saved under LoadRunner Vuser directory. If the boolean flag for the second argument is true, it uses LoadRunner's serialization method. If it is false, it uses Java's standard serialization method.
LoadRunner only unfolds objects when you are using LoadRunner's mechanism, (lr.deserialize(int, true)) and when the size of the object is smaller than the limit specified in the recording options. In cases where, for complication purposes, the object cannot be made sense out of or is larger than the size limit, LoadRunner automatically folds the object into serialbytexx.dat; sometimes it uses Java's standard mechanism, and therefore, it does not unfold the objects inside the script.
  lr.deserialize(String, int)
The second form records the serialized object inside the script source as a string and uses that as the object to be deserialized. In the below example _string15 will be used as an object to be deserialized
_rpmcommandexecutionserviceremote23 = _rpmcommandexecutionserviceremotehome45.create();
       
 _string15 = "com.retek.platform.bo.IdentifiableReference __CURRENT_OBJECT = {" +
              "com.retek.platform.bo.ObjectId objectId = {" +
                    "java.lang.Long value = {" +
                          "super = {" +
                          "}" +
                          "long value = #1#" +
                    "}" +
              "}" +
              "java.lang.String referencedClassName = #com.retek.rpm.domain.zonestructure.bo.ZoneGroupImpl#" +
              "java.lang.Long version = {" +
                    "super = {" +
                    "}" +
                    "long value = #0#" +
              "}" +
        "}";
 _identifiablereference1 = (com.retek.platform.bo.IdentifiableReference)lr.deserialize(_string15,14);  // RMIComponent

Having the larger serialized object inside the script source as a string is not recommended unless correlation is needed to the object. The bigger the Java serialized object, the more memory the JVM will need for VuGen to record it as unfolded. Thus, the recording may simply crash if "Object Size limit" is set to be too high in the recording options.

To increase/decrease the object size for serialization can be set through Recording options -Serialization tab - Limit Object Size

Correlation

Correlation for the serialized objects inside the script is straight forward. In the below example, the below value 14548 is replaced by a variable

_string32_StringBuffer.append("java.util.ArrayList __CURRENT_OBJECT = {" +
"}" +
                                            "com.retek.platform.bo.IdentifiableReference promotionReference = {" +
                                                  "com.retek.platform.bo.ObjectId objectId = {" +
                                                        "java.lang.Long value = {" +
                                                              "super = {" +
                                                              "}" +
                                                              //"long value = #14548#" +
                                                              "long value = ##" +
                                                        "}" +
                                                  "}" +

Object Inspection


In case you need to inspect an object from the script then import pf-joi-full.jar in LoadRunner and add following lines:

_clientcontext1 = com.retek.platform.service.ClientContext.getInstance();
        org.pf.joi.Inspector.inspect(_clientcontext1);

This will popup a window of JOI (Java Object Inspector) and you will see all members and data of the object

References

Enterprise Java Bean Response Time analysis – Santoshan Kumaran, Te-kai Liu
http://www.oracle.com/technetwork/java/javase/tech/index-jsp-136424.html
http://download.oracle.com/javase/1.4.2/docs/guide/security/permissions.html
http://grids.ucs.indiana.edu/ptliupages/projects/HPJava/theses/slim/dissertation/dissertation/node11.html

4 comments:

Anonymous said...

Nice article man. Very descriptive.


Check out full article on Java RMI Introduction here...

Alaska Mary said...

thank u for giving this best information..we are giving loadrunner online training

for IT the said...

Wow. This really made my day. Thanks a lot!

Java Training in Chennai | Online Java Training

Anonymous said...

Hi,
Is there any disadvantage of recording with folded serialized object option?
Will it cause lot of I/O when the program access the serialized object?
Scripting with folded serialized object speeds up the compiling time when the serialized object is really big. This is my experience.

You article is very helpful.
Thanks.

Dieu-Ai Le