Friday, September 2, 2016

Using the JRebel class loading tool with ADF projects

The JRebel tool, available from Zeroturnaround, is a class loading tool. It allows java class file changes to be loaded without any redeploys or restarts; it does this by extending the class loader and instrumenting classes. It not only will load changes to method bodies, but new methods, changes to interfaces, adding fields and enum values, and even property bundle changes.

It is a "java agent" plugin, available for Java 5+. They have many plugins for various frameworks (e.g. Groovy, Hibernate, myfaces, RESTEasy, Spring, Struts, Velocity), but it is the ADF one that caught my interest. I'll be focusing on how to install on a Windows desktop with JDeveloper, using the Integrated Weblogic. Other setups can likely be accommodated with little changes.

The really cool part for ADF developers though is that is also has the ability to handle changes to things like pagedef files, Application Module definitions and View Object definitions. This obviously comes in extremely handy. It is not free, but the licenses are pretty cheap. One important thing to note: JRebel doesn't magically know that you changed a java source file - it works by comparing dates on monitored folders. This means that you have to do a 'make' on your project so the .class file is updated. Usually this is relatively fast.

Is it a new idea? No, not at all. Existing methods have been around for quite some time now, but the JRebel solution is more comprehensive.

Existing method 1: Hot Deploy
When an application server (e.g. JBoss, Weblogic’s "Fast Swap") will redeploy upon code changes. Decent sized app could be 30 to 45 seconds.

Existing method 2: Hot Swap
Since Java 1.4, you can redefine classes inside a debugger session. However, this only works for method bodies.

Existing method 3: Throwaway class loaders
E.g. Apache jackrabbit, various schemes available with many containers including Spring, ATG, WebSphere, WL. Only works for Managed Components, and has other problems.

Firstly, JRebel can work from within JDeveloper and provides simple buttons to turn on and off. However, this only works with JDev 11.1.2 and above.  We are still using earlier versions so I opted for the "standalone" version. This simply means that you get it running with some JVM parameters rather than a more point-and-click configuration.

Prerequisites:
  • JDeveloper installed, 
  • JRebel standalone version downloaded
  • JRebel license file

Installation

1. Install the JRebel standalone product somewhere, e.g. C:\Programs\jrebel-6.1.0-nosetup.

2. Open a command window, and run the setup.

cd c:\Programs\jrebel-6.1.0-nosetup\jrebel
bin\setup.cmd

This should create a .jrebel folder in your home directory, e.g. C:\Users\jjames\.jrebel.

Activation

Put the license file in the .jrebel folder. In a cmd window, run the activate script:

cd C:\Programs\jrebel-6.1.0-nosetup\jrebel
bin\activate.cmd jrebel.lic

Modify Weblogic

Add to JAVA_OPTIONS:

-noverify -javaagent:C:\path_to_jar\jrebel.jar -Drebel.adf_core_plugin=true -Drebel.adf_faces_plugin=true

Note: you will need to boost your PermGen from default 64m to at least 128m. You may also need to boost your max heap size. If you still have problems, switch to a 64bit JVM.

-Xms512m -Xmx1536m -XX:PermSize=512m -XX:MaxPermSize=512m

Project Configuration

Apart from the JVM params, the only other configuration you really need is one rebel.xml file per JDev project that you want monitored. For your typical ADF application, that usually means a "Model" project and a "View Controller" project. You are simply pointing to the folders where the class files pagedef's, and JSP's live.

Here is a sample from one of my ADF projects. There is documentation on this here.

The Model project rebel.xml:

<?xml version = '1.0' encoding = 'UTF-8'?>
<application
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd"
    xmlns="http://www.zeroturnaround.com">
  <classpath>
    <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\Model\classes">
      <include name="*.class"/>
      <exclude name=".wlsjsps/**"/>
    </dir>
    <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\Model\src">
      <exclude name="*.java"/>
    </dir>
  </classpath>
</application>

The View Controller project rebel.xml:

<?xml version = '1.0' encoding = 'UTF-8'?>
<application
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd"
      xmlns="http://www.zeroturnaround.com">
   <classpath>
      <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\ViewController\adfmsrc"/>
      <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\ViewController\classes">
         <include name="**/*.class"/>
         <exclude name=".wlsjsps/**"/>
      </dir>
      <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\ViewController\src">
         <exclude name="**/*.java"/>
      </dir>
      <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\Model\classes">
         <include name="**/*.class"/>
         <exclude name=".wlsjsps/**"/>
      </dir>
   </classpath>
   <web>
      <link target="/">
         <dir name="C:\Projects\HelloWorldApp\ADF\HelloWorld\ViewController\public_html"/>
      </link>
   </web>
</application>

Starting Up

During the WLS startup, you should see some startup messages like the following:

2015-03-03 14:52:12 JRebel: ############################################################# 2015-03-03 14:52:12 JRebel: JRebel Legacy Agent 6.1.0 (201502250834) 2015-03-03 14:52:12 JRebel: (c) Copyright ZeroTurnaround AS, Estonia, Tartu. 2015-03-03 14:52:12 JRebel: 2015-03-03 14:52:12 JRebel: Over the last 1 days JRebel prevented 2015-03-03 14:52:12 JRebel: at least 0 redeploys/restarts saving you about 0 hours. 2015-03-03 14:52:12 JRebel: 2015-03-03 14:52:12 JRebel: Licensed to Jonathan James 2015-03-03 14:52:12 JRebel: ############################################################# .... <11-Mar-2015 3:45:40 o'clock PM EDT> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to STANDBY> <11-Mar-2015 3:45:40 o'clock PM EDT> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to STARTING> 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\ViewController\adfmsrc' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\ViewController\classes' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\ViewController\src' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\Model\classes' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\ViewController\public_html' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\Model\classes' will be monitored for changes. 2015-03-11 15:45:50 JRebel: Directory 'C:\CVS_RCeds\RCeds\ADF\RCeds\Model\src' will be monitored for changes.

When a class or other file is reloaded, you'll see something like:

2015-03-11 16:04:32 JRebel: Reloading class 'edu.rcpsc.eds.view.backing.ItemWorkList'.
or:
2015-03-11 16:13:31 JRebel-Mojarra: Reloading configuration